A modal window presenting content or seeking user input without navigating away from the current context.
Structure
Reusable Components
Bits UI provides a decent number of components to construct a Dialog. The idea is to provide a set of building blocks that can be used to create a variety of different layouts. It's recommended to use these components to build your own reusable Dialog components that can be used throughout your application.
The following example shows at a high level how you might create a reusable Dialog component. We've mixed and matched string props and snippets to demonstrate the flexibility of the component API. Use whatever makes sense for you.
You can then use the MyDialog component in your application like so:
Alternatively, you can define the snippets separately and pass them as props to the component:
Managing Open State
Bits UI provides flexible options for controlling and synchronizing the Dialog's open state.
Two-Way Binding
Use the bind:open directive for effortless two-way synchronization between your local state and the Dialog's internal state.
This setup enables opening the Dialog via the custom button and ensures the local isOpen state updates when the Dialog closes through any means (e.g., escape key).
Change Handler
You can also use the onOpenChange prop to update local state when the Dialog's open state changes. This is useful when you don't want two-way binding for one reason or another, or you want to perform additional logic when the Dialog opens or closes.
Managing Focus
Focus Trap
By default, when a Dialog is opened, focus will be trapped within the Dialog, preventing the user from interacting with the rest of the page. This follows the WAI-ARIA design pattern for modal dialogs.
Although it isn't recommended unless absolutely necessary, you can disabled this beahvior by setting the trapFocus prop to false on the Dialog.Content component.
Open Focus
By default, when a Dialog is opened, focus will be set to the first focusable element with the Dialog.Content. This ensures that users navigating my keyboard end up somewhere within the Dialog that they can interact with.
You can override this behavior using the onMountAutoFocus prop on the Dialog.Content component. It's highly recommended that you use this prop to focus something within the Dialog.
You'll first need to cancel the default behavior of focusing the first focusable element by cancelling the event passed to the onMountAutoFocus callback. You can then focus whatever you wish.
Close Focus
By default, when a Dialog is closed, focus will be set to the trigger element of the Dialog. You can override this behavior using the onDestroyAutoFocus prop on the Dialog.Content component.
You'll need to cancel the default behavior of focusing the trigger element by cancelling the event passed to the onDestroyAutoFocus callback, and then focus whatever you wish.
Scroll Lock
By default, when a Dialog is opened, scrolling the body will be disabled, which provides a more native experience for users. If you wish to disable this behavior, you can set the preventScroll prop to false on the Dialog.Content component.
Escape Keydown
By default, when a Dialog is open, pressing the Escape key will close the dialog. Bits UI provides a couple ways to override this behavior.
escapeKeydownBehavior
You can set the escapeKeydownBehavior prop to 'ignore' on the Dialog.Content component to prevent the dialog from closing when the Escape key is pressed.
onEscapeKeydown
You can also override the default behavior by cancelling the event passed to the onEscapeKeydown callback on the Dialog.Content component.
Interact Outside
By default, when a Dialog is open, pressing the outside the content will close the dialog. Bits UI provides a couple ways to override this behavior.
interactOutsideBehavior
You can set the interactOutsideBehavior prop to 'ignore' on the Dialog.Content component to prevent the dialog from closing when the user interacts outside the content.
onInteractOutside
You can also override the default behavior by cancelling the event passed to the onInteractOutside callback on the Dialog.Content component.
Nested Dialogs
Dialogs can be nested within each other to create more complex layouts.
Svelte Transitions
You can use the forceMount prop along with the child snippet to forcefully mount the Dialog.Content and Dialog.Overlay components to use Svelte Transitions or another animation library that requires more control.
Of course, this isn't the prettiest syntax, so it's recommended to create your own reusable content and overlay components that handle this logic if you intend to use this approach. For more information on using transitions with Bits UI components, see the Transitions documentation.
API Reference
Dialog.Root
The root component used to set and manage the state of the dialog.
Property
Type
Description
openbindable prop
boolean
Whether or not the dialog is open.
Default: false
onOpenChange
function
A callback function called when the open state changes.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
Dialog.Trigger
The element which opens the dialog on press.
Property
Type
Description
refbindable prop
HTMLButtonElement
The underlying DOM element being rendered. You can bind to this to get a reference to the element.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
child
Snippet
Use render delegation to render your own element. See delegation docs for more information.
Default: ——undefined
Data Attribute
Value
Description
data-dialog-trigger
''
Present on the trigger.
Dialog.Content
The content displayed within the dialog modal.
Property
Type
Description
onEscapeKeydown
function
Callback fired when an escape keydown event occurs in the floating content. You can call event.preventDefault() to prevent the default behavior of handling the escape keydown event.
Default: ——undefined
escapeKeydownBehavior
enum
The behavior to use when an escape keydown event occurs in the floating content. 'close' will close the content immediately. 'ignore' will prevent the content from closing. 'defer-otherwise-close' will defer to the parent element if it exists, otherwise it will close the content. 'defer-otherwise-ignore' will defer to the parent element if it exists, otherwise it will ignore the interaction.
Default: close
onInteractOutside
function
Callback fired when an outside interaction event completes, which is either a pointerup, mouseup, or touchend event, depending on the user's input device. You can call event.preventDefault() to prevent the default behavior of handling the outside interaction.
Default: ——undefined
onInteractOutsideStart
function
Callback fired when an outside interaction event starts, which is either a pointerdown, mousedown, or touchstart event, depending on the user's input device. You can call event.preventDefault() to prevent the continuation of the outside interaction.
Default: ——undefined
onFocusOutside
function
Callback fired when focus leaves the dismissable layer. You can call event.preventDefault() to prevent the default behavior on focus leaving the layer.
Default: ——undefined
interactOutsideBehavior
enum
The behavior to use when an interaction occurs outside of the floating content. 'close' will close the content immediately. 'ignore' will prevent the content from closing. 'defer-otherwise-close' will defer to the parent element if it exists, otherwise it will close the content. 'defer-otherwise-ignore' will defer to the parent element if it exists, otherwise it will ignore the interaction.
Default: close
onMountAutoFocus
function
Event handler called when auto-focusing the content as it is mounted. Can be prevented.
Default: ——undefined
onDestroyAutoFocus
function
Event handler called when auto-focusing the content as it is destroyed. Can be prevented.
Default: ——undefined
trapFocus
boolean
Whether or not to trap the focus within the content when open.
Default: true
forceMount
boolean
Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.
Default: false
preventOverflowTextSelection
boolean
When true, prevents the text selection from overflowing the bounds of the element.
Default: true
preventScroll
boolean
When true, prevents the body from scrolling when the content is open. This is useful when you want to use the content as a modal.
Default: true
refbindable prop
HTMLDivElement
The underlying DOM element being rendered. You can bind to this to get a reference to the element.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
child
Snippet
Use render delegation to render your own element. See delegation docs for more information.
Default: ——undefined
Data Attribute
Value
Description
data-state
enum
The state of the dialog.
data-dialog-content
''
Present on the content.
Dialog.Overlay
An overlay which covers the body when the dialog is open.
Property
Type
Description
forceMount
boolean
Whether or not to forcefully mount the content. This is useful if you want to use Svelte transitions or another animation library for the content.
Default: false
refbindable prop
HTMLDivElement
The underlying DOM element being rendered. You can bind to this to get a reference to the element.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
child
Snippet
Use render delegation to render your own element. See delegation docs for more information.
Default: ——undefined
Data Attribute
Value
Description
data-state
enum
The state of the dialog.
data-dialog-overlay
''
Present on the overlay.
Dialog.Portal
A portal which renders the dialog into the body when it is open.
Property
Type
Description
to
union
Where to render the content when it is open. Defaults to the body. Can be disabled by passing null
Default: body
disabled
boolean
Whether the portal is disabled or not. When disabled, the content will be rendered in its original DOM location.
Default: false
children
Snippet
The children content to render.
Default: ——undefined
Dialog.Close
A button used to close the dialog.
Property
Type
Description
refbindable prop
HTMLButtonElement
The underlying DOM element being rendered. You can bind to this to get a reference to the element.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
child
Snippet
Use render delegation to render your own element. See delegation docs for more information.
Default: ——undefined
Data Attribute
Value
Description
data-dialog-close
''
Present on the close button.
Dialog.Title
An accessibile title for the dialog.
Property
Type
Description
level
union
The heading level of the title.
Default: 3
refbindable prop
HTMLDivElement
The underlying DOM element being rendered. You can bind to this to get a reference to the element.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
child
Snippet
Use render delegation to render your own element. See delegation docs for more information.
Default: ——undefined
Data Attribute
Value
Description
data-dialog-title
''
Present on the title.
Dialog.Description
An accessibile description for the dialog.
Property
Type
Description
refbindable prop
HTMLDivElement
The underlying DOM element being rendered. You can bind to this to get a reference to the element.
Default: ——undefined
children
Snippet
The children content to render.
Default: ——undefined
child
Snippet
Use render delegation to render your own element. See delegation docs for more information.