Dialog

A dialog is a modal window that appears in front of app content to provide critical information or ask for a decision. It disables all app functionality when it appears and remains on screen until confirmed, dismissed, or a required action has been taken.

Features

  • Accessible by default with proper ARIA attributes
  • Focus management and focus trapping
  • Keyboard navigation support (Escape to close)
  • Click outside to dismiss
  • Multiple size options
  • Custom content and footer support
  • Smooth transitions

Props

PropTypeDefaultDescription
openbooleanfalseControls the visibility of the dialog
size'sm' \| 'md' \| 'lg' \| 'full''md'Sets the size of the dialog
titlestring''The title displayed in the dialog header
descriptionstring''A description text shown below the title
closeOnClickOutsidebooleantrueWhether clicking outside the dialog closes it
closeOnEscbooleantrueWhether pressing Escape closes the dialog
onClose() => void() => {}Callback function called when the dialog should close
children() => any() => ''Function that returns the content to be displayed in the dialog body
footer() => any() => ''Function that returns the footer content

Examples

Basic Dialog

<script>
    import Dialog from '$lib/components/Dialog/Dialog.svelte';
    import Button from '$lib/components/Button/Button.svelte';
    let open = false;
</script>

<Button 
    label="Open Dialog" 
    variant="primary" 
    onclick={() => open = true} 
/>

{#snippet dialogContent()}
    <p>This is the main content of the dialog.</p>
{/snippet}

<Dialog 
    {open} 
    onClose={() => open = false}
    title="Basic Dialog"
    description="This is a basic dialog with a title and description."
    children={dialogContent}
/>

Different Sizes

<script>
    import Dialog from '$lib/components/Dialog/Dialog.svelte';
    import Button from '$lib/components/Button/Button.svelte';
    let open = false;
    let size = 'md';
</script>

<div class="flex gap-4">
    <Button 
        label="Small Dialog" 
        variant="secondary" 
        onclick={() => { size = 'sm'; open = true; }} 
    />
    <Button 
        label="Medium Dialog" 
        variant="secondary" 
        onclick={() => { size = 'md'; open = true; }} 
    />
    <Button 
        label="Large Dialog" 
        variant="secondary" 
        onclick={() => { size = 'lg'; open = true; }} 
    />
    <Button 
        label="Full Screen Dialog" 
        variant="secondary" 
        onclick={() => { size = 'full'; open = true; }} 
    />
</div>

{#snippet dialogContent()}
    <p>This dialog can be displayed in different sizes.</p>
{/snippet}

<Dialog 
    {open} 
    {size}
    onClose={() => open = false}
    title="Resizable Dialog"
    children={dialogContent}
/>

Custom Footer

<script>
    import Dialog from '$lib/components/Dialog/Dialog.svelte';
    import Button from '$lib/components/Button/Button.svelte';
    let open = false;
</script>

<Button 
    label="Open Dialog with Footer" 
    variant="outline" 
    onclick={() => open = true} 
/>

{#snippet dialogContent()}
    <p>This dialog has custom footer buttons.</p>
{/snippet}

{#snippet dialogFooter()}
    <div class="flex justify-end gap-2">
        <Button 
            label="Cancel" 
            variant="ghost" 
            onclick={() => open = false} 
        />
        <Button 
            label="Confirm" 
            variant="primary" 
            onclick={() => { 
                // handle confirm 
                open = false;
            }} 
        />
    </div>
{/snippet}

<Dialog 
    {open} 
    onClose={() => open = false}
    title="Dialog with Footer"
    children={dialogContent}
    footer={dialogFooter}
/>

Non-Dismissible Dialog

<script>
    import Dialog from '$lib/components/Dialog/Dialog.svelte';
    import Button from '$lib/components/Button/Button.svelte';
    let open = false;
</script>

<Button 
    label="Open Non-Dismissible Dialog" 
    variant="ghost" 
    onclick={() => open = true} 
/>

{#snippet dialogContent()}
    <div class="flex flex-col gap-4">
        <p>This dialog can only be closed using the close button or programmatically.</p>
        <div class="flex justify-end">
            <Button 
                label="Close Dialog" 
                variant="primary" 
                onclick={() => open = false} 
            />
        </div>
    </div>
{/snippet}

<Dialog 
    {open} 
    closeOnClickOutside={false}
    closeOnEsc={false}
    onClose={() => open = false}
    title="Non-Dismissible Dialog"
    children={dialogContent}
/>

Accessibility

The Dialog component follows WAI-ARIA guidelines for modal dialogs:

  • Uses role="dialog" and aria-modal="true"
  • Properly manages focus when opened and closed
  • Traps focus within the dialog when open
  • Provides proper ARIA labeling with aria-labelledby and aria-describedby
  • Supports keyboard navigation
  • Returns focus to the trigger element when closed

Best Practices

  1. Use Clear Titles: Always provide a clear, descriptive title that indicates the purpose of the dialog.

  2. Keep Content Focused: Dialogs should present focused content and clear actions. Avoid overcrowding with too much information.

  3. Provide Clear Actions: When using action buttons in the footer, make their purpose clear and consider using different visual weights for primary and secondary actions.

  4. Handle Escape Key: Unless there’s a specific reason not to, allow users to close the dialog with the Escape key.

  5. Manage Focus: Ensure that focus is properly managed and that users can navigate through all interactive elements using the keyboard.

  6. Consider Mobile: When designing dialog content, ensure it works well on both desktop and mobile devices.

Related Components

  • Modal - A simpler version for basic modal windows
  • Sheet - A slide-out panel component
  • Drawer - A side panel component