Usage
Use a Button or any other component in the default slot of the Slideover.
Then, use the #content slot to add the content displayed when the Slideover is open.
<template>
<PSlideover>
<PButton label="Open" color="neutral" variant="subtle" />
<template #content>
<CorePlaceholder class="h-full m-4" />
</template>
</PSlideover>
</template>
You can also use the #header, #body and #footer slots to customize the Slideover's content.
Title
Use the title prop to set the title of the Slideover's header.
<template>
<PSlideover title="Slideover with title">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
Description
Use the description prop to set the description of the Slideover's header.
<template>
<PSlideover
title="Slideover with description"
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
>
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
Close
Use the close prop to customize or hide the close button (with false value) displayed in the Slideover's header.
You can pass any property from the Button component to customize it.
<template>
<PSlideover
title="Slideover with close button"
:close="{
color: 'primary',
variant: 'outline',
class: 'akar:rounded-full'
}"
>
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
#content slot is used as it's a part of the header.Close Icon
Use the close-icon prop to customize the close button Icon. Defaults to i-lucide:x.
<template>
<PSlideover title="Slideover with close button" close-icon="i-lucide:arrow-right">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
Side
Use the side prop to set the side of the screen where the Slideover will slide in from. Defaults to right.
<template>
<PSlideover side="left" title="Slideover with side">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full min-h-48" />
</template>
</PSlideover>
</template>
Inset
Use the inset prop to inset the Slideover from the edges.
<template>
<PSlideover side="right" inset title="Slideover with inset">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="min-w-96 min-h-96 size-full" />
</template>
</PSlideover>
</template>
Overlay
Use the overlay prop to control whether the Slideover has an overlay or not. Defaults to true.
<template>
<PSlideover :overlay="false" title="Slideover without overlay">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
Modal
Use the modal prop to control whether the Slideover blocks interaction with outside content. Defaults to true.
modal is set to false, the overlay is automatically disabled and outside content becomes interactive.<template>
<PSlideover :modal="false" title="Slideover interactive">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
Dismissible
Use the dismissible prop to control whether the Slideover is dismissible when clicking outside of it or pressing escape. Defaults to true.
close:prevent event will be emitted when the user tries to close it.modal: false with dismissible: false to make the Slideover's background interactive without closing it.<template>
<PSlideover :dismissible="false" title="Slideover non-dismissible">
<PButton label="Open" color="neutral" variant="subtle" />
<template #body>
<CorePlaceholder class="h-full" />
</template>
</PSlideover>
</template>
Examples
Control open state
You can control the open state by using the default-open prop or the v-model:open directive.
<script setup lang="ts">
import { defineShortcuts } from '#imports';
import { ref } from 'vue';
const open = ref(false);
defineShortcuts({
o: () => {
open.value = !open.value;
},
});
</script>
<template>
<PSlideover v-model:open="open">
<PButton
label="Open"
color="neutral"
variant="subtle"
/>
<template #content>
<CorePlaceholder class="m-4 h-full" />
</template>
</PSlideover>
</template>
defineShortcuts, you can toggle the Slideover by pressing O.Programmatic usage
You can use the useOverlay composable to open a Slideover programmatically.
App component which uses the OverlayProvider component.First, create a slideover component that will be opened programmatically:
<script setup lang="ts">
defineProps<{
count: number
}>()
const emit = defineEmits<{ close: [boolean] }>()
</script>
<template>
<PSlideover
:close="{ onClick: () => emit('close', false) }"
:description="`This slideover was opened programmatically ${count} times`"
>
<template #body>
<CorePlaceholder class="h-full" />
</template>
<template #footer>
<div class="flex gap-2">
<PButton color="neutral" label="Dismiss" @click="emit('close', false)" />
<PButton label="Success" @click="emit('close', true)" />
</div>
</template>
</PSlideover>
</template>
close event when the slideover is closed or dismissed here. You can emit any data through the close event, however, the event must be emitted in order to capture the return value.Then, use it in your app:
<script setup lang="ts">
import { useOverlay, useToast } from '#imports';
import { ref } from 'vue';
import SlideoverExample from './slideover-example.vue';
const count = ref(0);
const toast = useToast();
const overlay = useOverlay();
const slideover = overlay.create(SlideoverExample);
async function open() {
const instance = slideover.open({
count: count.value,
});
const shouldIncrement = await instance.result;
if (shouldIncrement) {
count.value++;
toast.add({
title: `Success: ${shouldIncrement}`,
color: 'success',
id: 'slideover-success',
});
// Update the count
slideover.patch({
count: count.value,
});
return;
}
toast.add({
title: `Dismissed: ${shouldIncrement}`,
color: 'error',
id: 'slideover-dismiss',
});
}
</script>
<template>
<PButton
label="Open"
color="neutral"
variant="subtle"
@click="open"
/>
</template>
emit('close').Nested slideovers
You can nest slideovers within each other.
<script setup lang="ts">
import { ref } from 'vue';
const first = ref(false);
const second = ref(false);
</script>
<template>
<PSlideover
v-model:open="first"
title="First slideover"
:pohon="{ footer: 'justify-end' }"
>
<PButton
color="neutral"
variant="subtle"
label="Open"
/>
<template #body>
<CorePlaceholder class="h-full" />
</template>
<template #footer>
<PButton
label="Close"
color="neutral"
variant="outline"
@click="first = false"
/>
<PSlideover
v-model:open="second"
title="Second slideover"
:pohon="{ footer: 'justify-end' }"
>
<PButton
label="Open second"
color="neutral"
/>
<template #body>
<CorePlaceholder class="h-full" />
</template>
<template #footer>
<PButton
label="Close"
color="neutral"
variant="outline"
@click="second = false"
/>
</template>
</PSlideover>
</template>
</PSlideover>
</template>
With footer slot
Use the #footer slot to add content after the Slideover's body.
<script setup lang="ts">
import { ref } from 'vue';
const open = ref(false);
</script>
<template>
<PSlideover
v-model:open="open"
title="Slideover with footer"
description="This is useful when you want a form in a Slideover."
:pohon="{ footer: 'justify-end' }"
>
<PButton
label="Open"
color="neutral"
variant="subtle"
/>
<template #body>
<CorePlaceholder class="h-full" />
</template>
<template #footer="{ close }">
<PButton
label="Cancel"
color="neutral"
variant="outline"
@click="close"
/>
<PButton
label="Submit"
color="neutral"
/>
</template>
</PSlideover>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
side | 'right' | "right" | "top" | "bottom" | "left"The side of the slideover. |
portal | true | string | false | true | HTMLElementRender the slideover in a portal.
|
title | string | |
description | string | |
content | ADialogContentProps & Partial<EmitsToProps<DialogContentImplEmits>>The content of the slideover.
| |
closeIcon | appConfig.pohon.icons.close | string | objectThe icon displayed in the close button. |
overlay | true | booleanRender an overlay behind the slideover. |
transition | true | booleanAnimate the slideover when opening or closing. |
close | true | booleanDisplay a close button to dismiss the slideover.
|
dismissible | true | booleanWhen |
modal | true | booleanThe modality of the dialog When set to |
inset | false | booleanWhether to inset the slideover from the edges. |
open | booleanThe controlled open state of the dialog. Can be binded as | |
defaultOpen | booleanThe open state of the dialog when it is initially rendered. Use when you do not need to control its open state. | |
pohon | { overlay?: ClassValue; content?: ClassValue; header?: ClassValue; wrapper?: ClassValue; body?: ClassValue; footer?: ClassValue; title?: ClassValue; description?: ClassValue; close?: ClassValue; } |
Slots
| Slot | Type |
|---|---|
default | { open: boolean; } |
content | { close: () => void; } |
header | { close: () => void; } |
title | object |
description | object |
actions | object |
close | { pohon: object; } |
body | { close: () => void; } |
footer | { close: () => void; } |
Emits
| Event | Type |
|---|---|
after:leave | [] |
after:enter | [] |
close:prevent | [] |
update:open | [value: boolean] |
Theme
Below is the theme configuration skeleton for the PSlideover. Since the component is provided unstyled by default, you will need to fill in these values to apply your own custom look and feel. If you prefer to use our pre-built, opinionated styling, you can instead use our UnoCSS preset, this docs is using it as well.
export default defineAppConfig({
pohon: {
slideover: {
slots: {
overlay: '',
content: '',
header: '',
wrapper: '',
body: '',
footer: '',
title: '',
description: '',
close: ''
},
variants: {
side: {
top: {
content: ''
},
right: {
content: ''
},
bottom: {
content: ''
},
left: {
content: ''
}
},
inset: {
true: {
content: ''
}
}
},
compoundVariants: []
}
}
};
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import pohon from 'pohon-ui/vite'
export default defineAppConfig({
pohon: {
slideover: {
slots: {
overlay: '',
content: '',
header: '',
wrapper: '',
body: '',
footer: '',
title: '',
description: '',
close: ''
},
variants: {
side: {
top: {
content: ''
},
right: {
content: ''
},
bottom: {
content: ''
},
left: {
content: ''
}
},
inset: {
true: {
content: ''
}
}
},
compoundVariants: []
}
}
};