Skip to main content

Modal

A flexible modal dialog component with multiple sizes, states, and accessibility features

Modal

The Modal component provides a flexible dialog system for displaying content that requires user attention or input. It includes comprehensive accessibility features, focus management, and customizable behaviors.

Modal Sizes

Different modal sizes for various content needs

Code

<Modal size="sm">Small modal content</Modal>
<Modal size="md">Medium modal content</Modal>
<Modal size="lg">Large modal content</Modal>
<Modal size="full">Full modal content</Modal>

Size specifications

Available size options and their dimensions

Small (sm) max-width: 400px Quick confirmations
Medium (md) max-width: 560px Standard content
Large (lg) max-width: 800px Complex forms
Full max-width: calc(100vw - 32px) Immersive experiences

API Reference

Props

PropTypeDefaultDescription
openbooleanfalseControls modal visibility
onClose() => void-Callback when modal should close
size'sm' \| 'md' \| 'lg' \| 'full''md'Modal size variant
closeOnBackdropbooleantrueClose modal when clicking backdrop
closeOnEscapebooleantrueClose modal when pressing Escape
showClosebooleantrueShow close button in top-right corner
classstring''Additional CSS classes

Sizes

  • Small (sm): 400px max-width, 16px padding - Ideal for confirmations
  • Medium (md): 560px max-width, 24px padding - Default for most content
  • Large (lg): 800px max-width, 32px padding - Rich content and forms
  • Full: Nearly full viewport, 40px padding - Complex workflows

Usage Examples

Basic Modal

<script>
  import Modal from '$lib/shared/components/overlays/Modal.svelte';

  let isOpen = false;
</script>

<Modal bind:open={isOpen} onClose={() => isOpen = false}>
  <h2>Modal Title</h2>
  <p>Modal content goes here.</p>
</Modal>

Form Modal

<Modal bind:open={formOpen} size="md" onClose={() => formOpen = false}>
  <h2>Edit Profile</h2>
  <form onsubmit|preventDefault={handleSubmit}>
    <div class="form-field">
      <label>Name</label>
      <input type="text" bind:value={name} />
    </div>
    <div class="modal-actions">
      <button type="submit">Save</button>
      <button type="button" onclick={() => formOpen = false}>Cancel</button>
    </div>
  </form>
</Modal>

Confirmation Dialog

<Modal
  bind:open={confirmOpen}
  size="sm"
  closeOnBackdrop={false}
  onClose={() => confirmOpen = false}
>
  <h2>Confirm Deletion</h2>
  <p>Are you sure you want to delete this item? This action cannot be undone.</p>
  <div class="modal-actions">
    <button onclick={handleDelete}>Delete</button>
    <button onclick={() => confirmOpen = false}>Cancel</button>
  </div>
</Modal>

Disable Close Methods

<!-- No backdrop close -->
<Modal
  bind:open={modal1}
  closeOnBackdrop={false}
  onClose={() => modal1 = false}
>
  Content here
</Modal>

<!-- No escape key close -->
<Modal
  bind:open={modal2}
  closeOnEscape={false}
  onClose={() => modal2 = false}
>
  Content here
</Modal>

<!-- No close button -->
<Modal
  bind:open={modal3}
  showClose={false}
  onClose={() => modal3 = false}
>
  Content here
</Modal>

Accessibility Features

Focus Management

  • Focus is trapped within the modal when open
  • Focus returns to the trigger element when closed
  • Tab cycles through focusable elements inside modal

Keyboard Navigation

  • Escape: Closes modal (if closeOnEscape is true)
  • Tab: Moves focus to next focusable element
  • Shift + Tab: Moves focus to previous focusable element

Screen Reader Support

  • Modal uses role="dialog" and aria-modal="true"
  • Proper ARIA labeling with aria-labelledby and aria-describedby
  • Background content is hidden from assistive technology

Body Scroll Lock

  • Body scrolling is disabled when modal is open
  • Scroll position is preserved when modal closes
  • Mobile touch scrolling is properly handled

Design Tokens

The Modal component uses the following design tokens:

  • Typography: --typography-heading-*, --typography-body-*
  • Spacing: --space-4, --space-6, --space-8, --space-10
  • Colors: --background, --border, --foreground
  • Shadows: --shadow-2xl
  • Radius: --radius-lg
  • Transitions: --transition-base

Best Practices

Content Guidelines

  • Keep modal content focused and actionable
  • Use clear, descriptive titles
  • Provide obvious ways to close or cancel
  • Avoid nested modals when possible

Size Selection

  • Use small modals for simple confirmations
  • Medium modals work for most forms and content
  • Large modals for complex forms or rich media
  • Full modals for multi-step workflows

Interaction Design

  • Always provide a way to close the modal
  • Use loading states for async operations
  • Validate forms before submission
  • Confirm destructive actions

Technical Notes

Performance

  • Modal content is only rendered when open is true
  • Focus trap and scroll lock are cleaned up automatically
  • Smooth animations with hardware acceleration

Browser Support

  • Full support for all modern browsers
  • Graceful degradation for older browsers
  • Mobile-optimized touch interactions

Framework Integration

  • Works with SvelteKit SSR
  • Compatible with Svelte 5 runes
  • TypeScript support included