# Dialog Documentation A modal window presenting content or seeking user input without navigating away from the current context. This is a documentation section that potentially contains examples, demos, and other useful information related to a specific part of Bits UI. When helping users with this documentation, you can ignore the classnames applied to the demos unless they are relevant to the user's issue. ```svelte New API key Create API key Create and manage API keys. You can create multiple keys to organize your applications.
API Key
Save
Close
``` ## Overview The Dialog component in Bits UI provides a flexible and accessible way to create modal dialogs in your Svelte applications. It follows a compound component pattern, allowing for fine-grained control over the dialog's structure and behavior while maintaining accessibility and ease of use. ## Key Features - **Compound Component Structure**: Offers a set of sub-components that work together to create a fully-featured dialog. - **Accessibility**: Built with WAI-ARIA guidelines in mind, ensuring keyboard navigation and screen reader support. - **Customizable**: Each sub-component can be styled and configured independently. - **Portal Support**: Content can be rendered in a portal, ensuring proper stacking context. - **Managed Focus**: Automatically manages focus, with the option to take control if needed. - **Flexible State Management**: Supports both controlled and uncontrolled state, allowing for full control over the dialog's open state. ## Architecture The Dialog component is composed of several sub-components, each with a specific role: - **Root**: The main container component that manages the state of the dialog. Provides context for all child components. - **Trigger**: A button that toggles the dialog's open state. - **Portal**: Renders its children in a portal, outside the normal DOM hierarchy. - **Overlay**: A backdrop that sits behind the dialog content. - **Content**: The main container for the dialog's content. - **Title**: Renders the dialog's title. - **Description**: Renders a description or additional context for the dialog. - **Close**: A button that closes the dialog. ## Structure Here's an overview of how the Dialog component is structured in code: ```svelte ``` ## Reusable Components Bits UI provides a comprehensive set of Dialog components that serve as building blocks for creating customized, reusable Dialog implementations. This approach offers flexibility in design while maintaining consistency and accessibility across your application. ### Building a Reusable Dialog The following example demonstrates how to create a versatile, reusable Dialog component using Bits UI building blocks. This implementation showcases the flexibility of the component API by combining props and snippets. MyDialog.svelte ```svelte {buttonText} {@render title()} {@render description()} {@render children?.()} Close Dialog ``` #### Usage with Inline Snippets ```svelte {#snippet title()} Account settings {/snippet} {#snippet description()} Manage your account settings and preferences. {/snippet} ``` #### Usage with Separate Snippets ```svelte {#snippet title()} Account settings {/snippet} {#snippet description()} Manage your account settings and preferences. {/snippet} ``` ### Best Practices - **Prop Flexibility**: Design your component to accept props for any nested components for maximum flexibility - **Styling Options**: Use tools like `clsx` to merge class overrides - **Binding Props**: Use `bind:` and expose `$bindable` props to provide consumers with full control - **Type Safety**: Use the exported types from Bits UI to type your component props ## Managing Open State This section covers how to manage the `open` state of the component. ### Two-Way Binding Use `bind:open` for simple, automatic state synchronization: ```svelte ``` ### Fully Controlled Use a [Function Binding](https://svelte.dev/docs/svelte/bind#Function-bindings) for complete control over the state's reads and writes. ```svelte ``` ## Focus Management Proper focus management is crucial for accessibility and user experience in modal dialogs. Bits UI's Dialog component provides several features to help you manage focus effectively. ### Focus Trap By default, the Dialog implements a focus trap, adhering to the WAI-ARIA design pattern for modal dialogs. This ensures that keyboard focus remains within the Dialog while it's open, preventing users from interacting with the rest of the page. #### Disabling the Focus Trap While not recommended, you can disable the focus trap if absolutely necessary: ```svelte ``` ##### Accessibility Warning Disabling the focus trap may compromise accessibility. Only do this if you have a specific reason and implement an alternative focus management strategy. ### Open Focus When a Dialog opens, focus is automatically set to the first focusable element within `Dialog.Content`. This ensures keyboard users can immediately interact with the Dialog contents. #### Customizing Initial Focus To specify which element receives focus when the Dialog opens, use the `onOpenAutoFocus` prop on `Dialog.Content`: ```svelte Open Dialog { e.preventDefault(); nameInput?.focus(); }} > ``` ##### Important Always ensure that *something* within the Dialog receives focus when it opens. This is crucial for maintaining keyboard navigation context and makes your users happy. ### Close Focus When a Dialog closes, focus returns to the element that triggered its opening (typically the `Dialog.Trigger`). #### Customizing Close Focus To change which element receives focus when the Dialog closes, use the `onCloseAutoFocus` prop on `Dialog.Content`: ```svelte Open Dialog { e.preventDefault(); nameInput?.focus(); }} > ``` ### Best Practices - Always maintain a clear focus management strategy for your Dialogs. - Ensure that focus is predictable and logical for keyboard users. - Test your focus management with keyboard navigation to verify its effectiveness. ## Advanced Behaviors Bits UI's Dialog component offers several advanced features to customize its behavior and enhance user experience. This section covers scroll locking, escape key handling, and interaction outside the dialog. ### Scroll Lock By default, when a Dialog opens, scrolling the body is disabled. This provides a more native-like experience, focusing user attention on the dialog content. #### Customizing Scroll Behavior To allow body scrolling while the dialog is open, use the `preventScroll` prop on `Dialog.Content`: ```svelte ``` ##### Note Enabling body scroll may affect user focus and accessibility. Use this option judiciously. ### Escape Key Handling By default, pressing the `Escape` key closes an open Dialog. Bits UI provides two methods to customize this behavior. #### Method 1: `escapeKeydownBehavior` The `escapeKeydownBehavior` prop allows you to customize the behavior taken by the component when the `Escape` key is pressed. It accepts one of the following values: - `'close'` (default): Closes the Dialog immediately. - `'ignore'` : Prevents the Dialog from closing. - `'defer-otherwise-close'` : If an ancestor Bits UI component also implements this prop, it will defer the closing decision to that component. Otherwise, the Dialog will close immediately. - `'defer-otherwise-ignore'` : If an ancestor Bits UI component also implements this prop, it will defer the closing decision to that component. Otherwise, the Dialog will ignore the key press and not close. To always prevent the Dialog from closing on Escape key press, set the `escapeKeydownBehavior` prop to `'ignore'` on `Dialog.Content`: ```svelte ``` #### Method 2: `onEscapeKeydown` For more granular control, override the default behavior using the `onEscapeKeydown` prop: ```svelte { e.preventDefault(); // do something else instead }} > ``` This method allows you to implement custom logic when the `Escape` key is pressed. ### Interaction Outside By default, interacting outside the Dialog content area closes the Dialog. Bits UI offers two ways to modify this behavior. #### Method 1: `interactOutsideBehavior` The `interactOutsideBehavior` prop allows you to customize the behavior taken by the component when an interaction (touch, mouse, or pointer event) occurs outside the content. It accepts one of the following values: - `'close'` (default): Closes the Dialog immediately. - `'ignore'` : Prevents the Dialog from closing. - `'defer-otherwise-close'` : If an ancestor Bits UI component also implements this prop, it will defer the closing decision to that component. Otherwise, the Dialog will close immediately. - `'defer-otherwise-ignore'` : If an ancestor Bits UI component also implements this prop, it will defer the closing decision to that component. Otherwise, the Dialog will ignore the event and not close. To always prevent the Dialog from closing when an interaction occurs outside the content, set the `interactOutsideBehavior` prop to `'ignore'` on `Dialog.Content`: ```svelte ``` #### Method 2: `onInteractOutside` For custom handling of outside interactions, you can override the default behavior using the `onInteractOutside` prop: ```svelte { e.preventDefault(); // do something else instead }} > ``` This approach allows you to implement specific behaviors when users interact outside the Dialog content. ### Best Practices - **Scroll Lock**: Consider your use case carefully before disabling scroll lock. It may be necessary for dialogs with scrollable content or for specific UX requirements. - **Escape Keydown**: Overriding the default escape key behavior should be done thoughtfully. Users often expect the escape key to close modals. - **Outside Interactions**: Ignoring outside interactions can be useful for important dialogs or multi-step processes, but be cautious not to trap users unintentionally. - **Accessibility**: Always ensure that any customizations maintain or enhance the dialog's accessibility. - **User Expectations**: Try to balance custom behaviors with common UX patterns to avoid confusing users. By leveraging these advanced features, you can create highly customized dialog experiences while maintaining usability and accessibility standards. ## Nested Dialogs Dialogs can be nested within each other to create more complex user interfaces: ```svelte {#snippet title()} First Dialog {/snippet} {#snippet description()} This is the first dialog. {/snippet} {#snippet title()} Second Dialog {/snippet} {#snippet description()} This is the second dialog. {/snippet} ``` ## Svelte Transitions The Dialog component can be enhanced with Svelte's built-in transition effects or other animation libraries. ### Using `forceMount` and `child` Snippets To apply Svelte transitions to Dialog components, use the `forceMount` prop in combination with the `child` snippet. This approach gives you full control over the mounting behavior and animation of `Dialog.Content` and `Dialog.Overlay`. ```svelte {#snippet child({ props, open })} {#if open}
{/if} {/snippet}
{#snippet child({ props, open })} {#if open}
{/if} {/snippet}
``` In this example: - The `forceMount` prop ensures the components are always in the DOM. - The `child` snippet provides access to the open state and component props. - Svelte's `#if` block controls when the content is visible. - Transition directives ( `transition:fade` and `transition:fly` ) apply the animations. ### Best Practices For cleaner code and better maintainability, consider creating custom reusable components that encapsulate this transition logic. MyDialogOverlay.svelte ```svelte {#snippet child({ props, open })} {#if open}
{@render children?.()}
{/if} {/snippet}
``` You can then use the `MyDialogOverlay` component alongside the other `Dialog` primitives throughout your application: ```svelte Open ``` ## Working with Forms ### Form Submission When using the `Dialog` component, often you'll want to submit a form or perform an asynchronous action and then close the dialog. This can be done by waiting for the asynchronous action to complete, then programmatically closing the dialog. ```svelte Confirm your action Are you sure you want to do this?
{ wait(1000).then(() => (open = false)); }} >