Usage
Use a Button or any other component in the default slot of the Modal.
Then, use the #content slot to add the content displayed when the Modal is open.
{
"wait": "Loading client-side content..."
}You can also use the #header, #body and #footer slots to customize the Modal's content.
Title
Use the title prop to set the title of the Modal's header.
{
"wait": "Loading client-side content..."
}Description
Use the description prop to set the description of the Modal's header.
{
"wait": "Loading client-side content..."
}Close
Use the close prop to customize or hide the close button (with false value) displayed in the Modal's header.
You can pass any property from the Button component to customize it.
{
"wait": "Loading client-side content..."
}#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.
{
"wait": "Loading client-side content..."
}Transition
Use the transition prop to control whether the Modal is animated or not. Defaults to true.
{
"wait": "Loading client-side content..."
}Overlay
Use the overlay prop to control whether the Modal has an overlay or not. Defaults to true.
{
"wait": "Loading client-side content..."
}Overlay blur
If you want to disable background blur, you should use the overlayBlur prop.
The overlayBlur prop has 3 options:
auto: (default) when the user has not requested reduced motionon: always use bluroff: do not use blur
{
"wait": "Loading client-side content..."
}Modal
Use the modal prop to control whether the Modal blocks interaction with outside content. Defaults to true.
modal is set to false, the overlay is automatically disabled and outside content becomes interactive.{
"wait": "Loading client-side content..."
}Dismissible
Use the dismissible prop to control whether the Modal 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 Modal's background interactive without closing it.{
"wait": "Loading client-side content..."
}Scrollable Soon
Use the scrollable prop to make the Modal's content scrollable within the overlay.
modal: false is not compatible and overlay: false only removes the background.{
"wait": "Loading client-side content..."
}Fullscreen
Use the fullscreen prop to make the Modal fullscreen.
{
"wait": "Loading client-side content..."
}Examples
Control open state
You can control the open state by using the default-open prop or the v-model:open directive.
defineShortcuts, you can toggle the Modal by pressing O.Programmatic usage
You can use the useOverlay composable to open a Modal programmatically.
App component which uses the OverlayProvider component.First, create a modal component that will be opened programmatically:
close event when the modal 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:
emit('close').Nested modals
You can nest modals within each other.
With footer slot
Use the #footer slot to add content after the Modal's body.
With command palette
You can use a CommandPalette component inside the Modal's content.
API
Props
Slots
Emits
Theme
export default defineAppConfig({
b24ui: {
modal: {
slots: {
overlay: 'fixed inset-0',
content: 'light bg-(--popup-window-background-color) flex flex-col gap-[20px] focus:outline-none p-[24px] pt-[20px]',
contentWrapper: 'flex flex-col gap-[15px] pt-[4px]',
header: 'flex items-start justify-between gap-[6px]',
wrapper: '',
body: 'flex-1 text-(length:--ui-font-size-md) leading-normal',
footer: 'flex items-center justify-between gap-[10px] border-t border-t-1 border-t-(--ui-color-divider-default) pt-[18px]',
title: 'font-[family-name:var(--ui-font-family-primary)] text-(--b24ui-typography-label-color) font-(--ui-font-weight-medium) mb-0 text-[calc(var(--ui-font-size-2xl)+2px)]/(--ui-font-size-2xl)',
description: 'mt-1 text-(--b24ui-typography-description-color) text-(length:--ui-font-size-sm)',
close: '-mt-[4px]'
},
variants: {
overlayBlur: {
auto: {
overlay: 'motion-safe:backdrop-blur-[2px]'
},
on: {
overlay: 'backdrop-blur-[2px]'
},
off: {
overlay: ''
}
},
transition: {
true: {
overlay: 'motion-safe:data-[state=open]:animate-[fade-in_200ms_ease-out] motion-safe:data-[state=closed]:animate-[fade-out_200ms_ease-in]',
content: 'motion-safe:data-[state=open]:animate-[scale-in_200ms_ease-out] motion-safe:data-[state=closed]:animate-[scale-out_200ms_ease-in]'
}
},
fullscreen: {
true: {
content: 'inset-0'
},
false: {
content: 'w-[calc(100vw-2rem)] max-w-[32rem] rounded-[calc(var(--popup-window-border-radius)-2px)] shadow-lg',
contentWrapper: ''
}
},
overlay: {
true: {
overlay: 'bg-[#003366]/20'
}
},
scrollable: {
true: {
overlay: 'overflow-y-auto',
content: 'relative'
},
false: {
content: 'fixed',
body: 'overflow-y-auto'
}
},
scrollbarThin: {
true: {
body: 'scrollbar-thin'
}
}
},
compoundVariants: [
{
scrollable: true,
fullscreen: false,
class: {
overlay: 'grid place-items-center p-4 sm:py-8'
}
},
{
scrollable: false,
fullscreen: false,
class: {
content: 'top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-h-[calc(100dvh-2rem)] sm:max-h-[calc(100dvh-4rem)]',
contentWrapper: 'overflow-hidden'
}
}
],
defaultVariants: {
scrollbarThin: true,
overlayBlur: 'auto'
}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import bitrix24UIPluginVite from '@bitrix24/b24ui-nuxt/vite'
export default defineConfig({
plugins: [
vue(),
bitrix24UIPluginVite({
b24ui: {
modal: {
slots: {
overlay: 'fixed inset-0',
content: 'light bg-(--popup-window-background-color) flex flex-col gap-[20px] focus:outline-none p-[24px] pt-[20px]',
contentWrapper: 'flex flex-col gap-[15px] pt-[4px]',
header: 'flex items-start justify-between gap-[6px]',
wrapper: '',
body: 'flex-1 text-(length:--ui-font-size-md) leading-normal',
footer: 'flex items-center justify-between gap-[10px] border-t border-t-1 border-t-(--ui-color-divider-default) pt-[18px]',
title: 'font-[family-name:var(--ui-font-family-primary)] text-(--b24ui-typography-label-color) font-(--ui-font-weight-medium) mb-0 text-[calc(var(--ui-font-size-2xl)+2px)]/(--ui-font-size-2xl)',
description: 'mt-1 text-(--b24ui-typography-description-color) text-(length:--ui-font-size-sm)',
close: '-mt-[4px]'
},
variants: {
overlayBlur: {
auto: {
overlay: 'motion-safe:backdrop-blur-[2px]'
},
on: {
overlay: 'backdrop-blur-[2px]'
},
off: {
overlay: ''
}
},
transition: {
true: {
overlay: 'motion-safe:data-[state=open]:animate-[fade-in_200ms_ease-out] motion-safe:data-[state=closed]:animate-[fade-out_200ms_ease-in]',
content: 'motion-safe:data-[state=open]:animate-[scale-in_200ms_ease-out] motion-safe:data-[state=closed]:animate-[scale-out_200ms_ease-in]'
}
},
fullscreen: {
true: {
content: 'inset-0'
},
false: {
content: 'w-[calc(100vw-2rem)] max-w-[32rem] rounded-[calc(var(--popup-window-border-radius)-2px)] shadow-lg',
contentWrapper: ''
}
},
overlay: {
true: {
overlay: 'bg-[#003366]/20'
}
},
scrollable: {
true: {
overlay: 'overflow-y-auto',
content: 'relative'
},
false: {
content: 'fixed',
body: 'overflow-y-auto'
}
},
scrollbarThin: {
true: {
body: 'scrollbar-thin'
}
}
},
compoundVariants: [
{
scrollable: true,
fullscreen: false,
class: {
overlay: 'grid place-items-center p-4 sm:py-8'
}
},
{
scrollable: false,
fullscreen: false,
class: {
content: 'top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-h-[calc(100dvh-2rem)] sm:max-h-[calc(100dvh-4rem)]',
contentWrapper: 'overflow-hidden'
}
}
],
defaultVariants: {
scrollbarThin: true,
overlayBlur: 'auto'
}
}
}
})
]
})