Utilisation
Use a Button or any other component in the default slot of the Slideover.
Ensuite, utilisez l'emplacement #content pour ajouter le contenu affiché lorsque le Slideover est ouvert.
<template>
<USlideover>
<UButton label="Open" color="neutral" variant="subtle" />
<template #content>
<Placeholder class="h-full m-4" />
</template>
</USlideover>
</template>Vous pouvez également utiliser les emplacements #header, #body et #footer pour personnaliser le contenu du Slideover.
Titre
Utilisez la prop title pour définir le titre de l'en-tête du Slideover.
<template>
<USlideover title="Slideover with title">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>Description
Utilisez la prop description pour définir la description de l'en-tête du Slideover.
<template>
<USlideover
title="Slideover with description"
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
>
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>Fermeture
Utilisez la prop close pour personnaliser ou masquer le bouton de fermeture (avec la valeur false) affiché dans l'en-tête du Slideover.
Puede pasar cualquier propiedad del componente Button para personalizarlo.
<template>
<USlideover
title="Slideover with close button"
:close="{
color: 'primary',
variant: 'outline',
class: 'rounded-full'
}"
>
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>#content, ya que es parte del encabezado.Fermer l'icône
Utilisez la prop close-icon pour personnaliser le bouton de fermeture Icon.
<template>
<USlideover title="Slideover with close button" close-icon="i-lucide-arrow-right">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>app.config.ts sous la touche ui.icons.close.vite.config.ts sous la touche ui.icons.close.Side
Utilisez le prop side pour définir le côté de l'écran où le Slideover va glisser de. Defaults à right.
<template>
<USlideover side="left" title="Slideover with side">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full min-h-48" />
</template>
</USlideover>
</template>Inset: badge{label="4.3+" class="align-text-top"}
Utilisez le prop inset pour insérer le Slideover depuis les bords.
<template>
<USlideover side="right" inset title="Slideover with inset">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="min-w-96 min-h-96 size-full" />
</template>
</USlideover>
</template>Transition
Utilisez la prop transition pour contrôler si le Slideover est animé ou non.
<template>
<USlideover :transition="false" title="Slideover without transition">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>Overlay
Utilisez la prop overlay pour contrôler si le Slideover a une superposition ou non. Par défaut, true.
<template>
<USlideover :overlay="false" title="Slideover without overlay">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>Modale
Utilisez la prop modal pour contrôler si le Slideover bloque l'interaction avec le contenu extérieur.
modal est défini sur false, la superposition est automatiquement désactivée et le contenu extérieur devient interactif.<template>
<USlideover :modal="false" title="Slideover interactive">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>Dismissible
Utilisez la prop dismissible pour contrôler si le Slideover est éliminable lorsque vous cliquez en dehors de celui-ci ou appuyez sur escape.
close:prevent sera émis lorsque l'utilisateur essaiera de le fermer.modal: false avec dismissible: false pour rendre l'arrière-plan du Slideover interactif sans le fermer.<template>
<USlideover :dismissible="false" title="Slideover non-dismissible">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>Unmount: badge{label="4.10+" class="align-text-top"}
Utilisez la prop unmount-on-hide pour empêcher que le contenu du Slideover ne soit démonté lorsqu 'il est fermé. Par défaut, true.
<template>
<USlideover :unmount-on-hide="false" title="Slideover">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
</USlideover>
</template>portal est définie sur false, le contenu est également rendu sur le serveur. Ceci est utile pour rendre un slideover ouvert pendant SSR sans flash sur le chargement de la page, ou pour exposer son contenu pour le référencement.Exemples
Control état ouvert
Vous pouvez contrôler l'état ouvert en utilisant la prop default-open ou la directive v-model:open.
<script setup lang="ts">
const open = ref(false)
defineShortcuts({
o: () => open.value = !open.value
})
</script>
<template>
<USlideover v-model:open="open">
<UButton label="Open" color="neutral" variant="subtle" />
<template #content>
<Placeholder class="h-full m-4" />
</template>
</USlideover>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const open = ref(false)
defineShortcuts({
o: () => open.value = !open.value
})
</script>
<template>
<USlideover v-model:open="open">
<UButton label="Open" color="neutral" variant="subtle" />
<template #content>
<Placeholder class="h-full m-4" />
</template>
</USlideover>
</template>
defineShortcuts, vous pouvez basculer le Slideover en appuyant sur: kbd{value="O"}.Utilisation programmatique
Vous pouvez utiliser le composable useOverlay pour ouvrir un Slideover par programmation.
App qui utilise le composant OverlayProvider.Tout d'abord, créez un composant de glissement qui sera ouvert par programme:
<script setup lang="ts">
defineProps<{
count: number
}>()
const emit = defineEmits<{ close: [boolean] }>()
</script>
<template>
<USlideover
:close="{ onClick: () => emit('close', false) }"
:description="`This slideover was opened programmatically ${count} times`"
>
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer>
<div class="flex gap-2">
<UButton color="neutral" label="Dismiss" @click="emit('close', false)" />
<UButton label="Success" @click="emit('close', true)" />
</div>
</template>
</USlideover>
</template>close lorsque le slideover est fermé ou rejeté ici. Vous pouvez émettre n'importe quelle donnée via l'événement close, et ces données deviennent la valeur résolue de open(). L'événement doit être émis pour que la promesse se résolve.Ensuite, utilisez-le dans votre app:
<script setup lang="ts">
import { LazySlideoverExample } from '#components'
const count = ref(0)
const toast = useToast()
const overlay = useOverlay()
const slideover = overlay.create(LazySlideoverExample)
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>
<UButton label="Open" color="neutral" variant="subtle" @click="open" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { LazySlideoverExample } from '#components'
const count = ref(0)
const toast = useToast()
const overlay = useOverlay()
const slideover = overlay.create(LazySlideoverExample)
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>
<UButton label="Open" color="neutral" variant="subtle" @click="open" />
</template>
emit('close').Slide-overs imbriqués
Vous pouvez imbriquer des glissières les unes dans les autres.
<script setup lang="ts">
const first = ref(false)
const second = ref(false)
</script>
<template>
<USlideover v-model:open="first" title="First slideover" :ui="{ footer: 'justify-end' }">
<UButton color="neutral" variant="subtle" label="Open" />
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer>
<UButton label="Close" color="neutral" variant="outline" @click="first = false" />
<USlideover v-model:open="second" title="Second slideover" :ui="{ footer: 'justify-end' }">
<UButton label="Open second" color="neutral" />
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer>
<UButton label="Close" color="neutral" variant="outline" @click="second = false" />
</template>
</USlideover>
</template>
</USlideover>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const first = ref(false)
const second = ref(false)
</script>
<template>
<USlideover v-model:open="first" title="First slideover" :ui="{ footer: 'justify-end' }">
<UButton color="neutral" variant="subtle" label="Open" />
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer>
<UButton label="Close" color="neutral" variant="outline" @click="first = false" />
<USlideover v-model:open="second" title="Second slideover" :ui="{ footer: 'justify-end' }">
<UButton label="Open second" color="neutral" />
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer>
<UButton label="Close" color="neutral" variant="outline" @click="second = false" />
</template>
</USlideover>
</template>
</USlideover>
</template>
With slot de pied de page
Utilisez le slot #footer pour ajouter du contenu après le corps du Slideover.
<script setup lang="ts">
const open = ref(false)
</script>
<template>
<USlideover v-model:open="open" title="Slideover with footer" description="This is useful when you want a form in a Slideover." :ui="{ footer: 'justify-end' }">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer="{ close }">
<UButton label="Cancel" color="neutral" variant="outline" @click="close" />
<UButton label="Submit" color="neutral" />
</template>
</USlideover>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const open = ref(false)
</script>
<template>
<USlideover v-model:open="open" title="Slideover with footer" description="This is useful when you want a form in a Slideover." :ui="{ footer: 'justify-end' }">
<UButton label="Open" color="neutral" variant="subtle" />
<template #body>
<Placeholder class="h-full" />
</template>
<template #footer="{ close }">
<UButton label="Cancel" color="neutral" variant="outline" @click="close" />
<UButton label="Submit" color="neutral" />
</template>
</USlideover>
</template>
API équipement
Props
| Prop | Default | Type |
|---|---|---|
title | string | |
description | string | |
content | DialogContentProps & Partial<EmitsToProps<DialogContentImplEmits>>The content of the slideover. | |
overlay | true | boolean Render an overlay behind the slideover. |
transition | true | boolean Animate the slideover when opening or closing. |
side | 'right' | "right" | "top" | "bottom" | "left"The side of the slideover. |
inset | false | boolean Whether to inset the slideover from the edges. |
portal | true | string | false | true | HTMLElementRender the slideover in a portal. |
close | true | boolean | Omit<ButtonProps, LinkPropsKeys> Display a close button to dismiss the slideover.
|
closeIcon | appConfig.ui.icons.close | anyThe icon displayed in the close button. |
dismissible | true | boolean When |
open | boolean The controlled open state of the dialog. Can be binded as | |
defaultOpen | boolean The open state of the dialog when it is initially rendered. Use when you do not need to control its open state. | |
modal | true | boolean The modality of the dialog When set to |
unmountOnHide | true | boolean When set to |
ui | { overlay?: SlotClass; content?: SlotClass; header?: SlotClass; wrapper?: SlotClass; body?: SlotClass; footer?: SlotClass; title?: SlotClass; description?: SlotClass; close?: SlotClass; } |
Slots
| Slot | Type |
|---|---|
default | { open: boolean; } |
content | { close: () => void; } |
header | { close: () => void; } |
title | {} |
description | {} |
actions | {} |
close | { ui: object; } |
body | { close: () => void; } |
footer | { close: () => void; } |
Emits
| Event | Type |
|---|---|
leave | [] |
after:leave | [] |
enter | [] |
after:enter | [] |
close:prevent | [] |
update:open | [value: boolean] |
Thème
export default defineAppConfig({
ui: {
slideover: {
slots: {
overlay: 'fixed inset-0 bg-elevated/75',
content: 'fixed bg-default divide-y divide-default sm:ring ring-default sm:shadow-lg flex flex-col focus:outline-none',
header: 'flex items-center gap-1.5 p-4 sm:px-6 min-h-(--ui-header-height)',
wrapper: '',
body: 'flex-1 overflow-y-auto p-4 sm:p-6',
footer: 'flex items-center gap-1.5 p-4 sm:px-6',
title: 'text-highlighted font-semibold',
description: 'mt-1 text-muted text-sm',
close: 'absolute top-4 end-4'
},
variants: {
side: {
top: {
content: ''
},
right: {
content: 'max-w-md'
},
bottom: {
content: ''
},
left: {
content: 'max-w-md'
}
},
inset: {
true: {
content: 'rounded-lg'
}
},
transition: {
true: {
overlay: 'data-[state=open]:animate-[fade-in_200ms_var(--ease-out)] data-[state=closed]:animate-[fade-out_200ms_var(--ease-out)]'
}
}
},
compoundVariants: [
{
side: 'top',
inset: true,
class: {
content: 'max-h-[calc(100%-2rem)] inset-x-4 top-4'
}
},
{
side: 'top',
inset: false,
class: {
content: 'max-h-full inset-x-0 top-0'
}
},
{
side: 'right',
inset: true,
class: {
content: 'w-[calc(100%-2rem)] inset-y-4 right-4'
}
},
{
side: 'right',
inset: false,
class: {
content: 'w-full inset-y-0 right-0'
}
},
{
side: 'bottom',
inset: true,
class: {
content: 'max-h-[calc(100%-2rem)] inset-x-4 bottom-4'
}
},
{
side: 'bottom',
inset: false,
class: {
content: 'max-h-full inset-x-0 bottom-0'
}
},
{
side: 'left',
inset: true,
class: {
content: 'w-[calc(100%-2rem)] inset-y-4 left-4'
}
},
{
side: 'left',
inset: false,
class: {
content: 'w-full inset-y-0 left-0'
}
},
{
transition: true,
side: 'top',
class: {
content: 'data-[state=open]:animate-[slide-in-from-top_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-top_200ms_var(--ease-out)]'
}
},
{
transition: true,
side: 'right',
class: {
content: 'data-[state=open]:animate-[slide-in-from-right_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-right_200ms_var(--ease-out)]'
}
},
{
transition: true,
side: 'bottom',
class: {
content: 'data-[state=open]:animate-[slide-in-from-bottom_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-bottom_200ms_var(--ease-out)]'
}
},
{
transition: true,
side: 'left',
class: {
content: 'data-[state=open]:animate-[slide-in-from-left_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-left_200ms_var(--ease-out)]'
}
}
]
}
}
})import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
slideover: {
slots: {
overlay: 'fixed inset-0 bg-elevated/75',
content: 'fixed bg-default divide-y divide-default sm:ring ring-default sm:shadow-lg flex flex-col focus:outline-none',
header: 'flex items-center gap-1.5 p-4 sm:px-6 min-h-(--ui-header-height)',
wrapper: '',
body: 'flex-1 overflow-y-auto p-4 sm:p-6',
footer: 'flex items-center gap-1.5 p-4 sm:px-6',
title: 'text-highlighted font-semibold',
description: 'mt-1 text-muted text-sm',
close: 'absolute top-4 end-4'
},
variants: {
side: {
top: {
content: ''
},
right: {
content: 'max-w-md'
},
bottom: {
content: ''
},
left: {
content: 'max-w-md'
}
},
inset: {
true: {
content: 'rounded-lg'
}
},
transition: {
true: {
overlay: 'data-[state=open]:animate-[fade-in_200ms_var(--ease-out)] data-[state=closed]:animate-[fade-out_200ms_var(--ease-out)]'
}
}
},
compoundVariants: [
{
side: 'top',
inset: true,
class: {
content: 'max-h-[calc(100%-2rem)] inset-x-4 top-4'
}
},
{
side: 'top',
inset: false,
class: {
content: 'max-h-full inset-x-0 top-0'
}
},
{
side: 'right',
inset: true,
class: {
content: 'w-[calc(100%-2rem)] inset-y-4 right-4'
}
},
{
side: 'right',
inset: false,
class: {
content: 'w-full inset-y-0 right-0'
}
},
{
side: 'bottom',
inset: true,
class: {
content: 'max-h-[calc(100%-2rem)] inset-x-4 bottom-4'
}
},
{
side: 'bottom',
inset: false,
class: {
content: 'max-h-full inset-x-0 bottom-0'
}
},
{
side: 'left',
inset: true,
class: {
content: 'w-[calc(100%-2rem)] inset-y-4 left-4'
}
},
{
side: 'left',
inset: false,
class: {
content: 'w-full inset-y-0 left-0'
}
},
{
transition: true,
side: 'top',
class: {
content: 'data-[state=open]:animate-[slide-in-from-top_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-top_200ms_var(--ease-out)]'
}
},
{
transition: true,
side: 'right',
class: {
content: 'data-[state=open]:animate-[slide-in-from-right_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-right_200ms_var(--ease-out)]'
}
},
{
transition: true,
side: 'bottom',
class: {
content: 'data-[state=open]:animate-[slide-in-from-bottom_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-bottom_200ms_var(--ease-out)]'
}
},
{
transition: true,
side: 'left',
class: {
content: 'data-[state=open]:animate-[slide-in-from-left_200ms_var(--ease-out)] data-[state=closed]:animate-[slide-out-to-left_200ms_var(--ease-out)]'
}
}
]
}
}
})
]
})