Overlay

Modal

A modal overlay for confirmations, forms, alerts, and custom content with support for scrollable, fullscreen, and non-dismissible modes.

Playground

Experiment with different props in real-time.

Basic Usage

Import and use the Modal component with bind:open, a title, and description.

<script lang="ts">
  import { Modal, Button } from 'sv5ui';

  let open = $state(false);
</script>

<Button label="Open Modal" onclick={() => (open = true)} />

<Modal
  bind:open
  title="Basic Modal"
  description="This is a simple modal with a title and description."
>
  {#snippet body()}
    <p>This is the body content of the modal.</p>
  {/snippet}
</Modal>

With Footer

Add action buttons using the footer snippet.

<script lang="ts">
  import { Modal, Button } from 'sv5ui';

  let open = $state(false);
</script>

<Button label="Open Modal" onclick={() => (open = true)} />

<Modal
  bind:open
  title="Confirm Action"
  description="Are you sure you want to proceed?"
>
  {#snippet body()}
    <p>This action cannot be undone. Please confirm to continue.</p>
  {/snippet}

  {#snippet footer()}
    <Button variant="outline" color="surface" label="Cancel" onclick={() => (open = false)} />
    <Button label="Confirm" onclick={() => (open = false)} />
  {/snippet}
</Modal>

Scrollable

Enable the scrollable prop for modals with long content.

<script lang="ts">
  import { Modal, Button } from 'sv5ui';

  let open = $state(false);
</script>

<Button label="Open Scrollable" onclick={() => (open = true)} />

<Modal
  bind:open
  title="Terms of Service"
  scrollable
>
  {#snippet body()}
    <div class="space-y-4">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
      <!-- Long scrollable content -->
    </div>
  {/snippet}
</Modal>

Fullscreen

Use the fullscreen prop to make the modal fill the entire viewport.

<script lang="ts">
  import { Modal, Button } from 'sv5ui';

  let open = $state(false);
</script>

<Button label="Open Fullscreen" onclick={() => (open = true)} />

<Modal
  bind:open
  title="Fullscreen Modal"
  fullscreen
>
  {#snippet body()}
    <p>This modal fills the entire viewport.</p>
  {/snippet}
</Modal>

Custom Header

Use the header snippet to fully customize the header layout.

<script lang="ts">
  import { Modal, Button } from 'sv5ui';

  let open = $state(false);
</script>

<Button label="Open Custom Header" onclick={() => (open = true)} />

<Modal bind:open>
  {#snippet header()}
    <div class="flex items-center gap-3">
      <div class="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10">
        <span class="text-primary text-lg">!</span>
      </div>
      <div>
        <h3 class="text-lg font-semibold">Custom Header</h3>
        <p class="text-sm text-on-surface/60">With a custom icon layout</p>
      </div>
    </div>
  {/snippet}

  {#snippet body()}
    <p>The header snippet lets you fully customize the header area.</p>
  {/snippet}
</Modal>

Non-dismissible

Set dismissible={false} to prevent closing by clicking outside or pressing Escape.

<script lang="ts">
  import { Modal, Button } from 'sv5ui';

  let open = $state(false);
</script>

<Button label="Open Non-dismissible" onclick={() => (open = true)} />

<Modal
  bind:open
  title="Important Notice"
  dismissible={false}
>
  {#snippet body()}
    <p>This modal cannot be closed by clicking outside or pressing Escape. You must use the button below.</p>
  {/snippet}

  {#snippet footer()}
    <Button label="I Understand" onclick={() => (open = false)} />
  {/snippet}
</Modal>

UI Slots

Use the ui prop to override classes on specific internal elements of the Modal.

SlotDescription
overlayBackdrop behind the modal — controls background color and opacity
contentMain modal container — controls width, padding, border radius, shadow
headerTop section containing title and description — controls layout and spacing
wrapperWraps the title and description text — controls text layout
titleModal title text — controls font size, weight, color
descriptionModal description text — controls font size and opacity
bodyMain content area — controls padding and overflow behavior
footerBottom section for actions — controls layout, gap, and alignment
closeClose button in the header — controls position, size, and icon

Snippets

Use Svelte 5 snippets to customize specific parts of the Modal.

SnippetTypeDescription
childrenSnippetTrigger element — clicking opens the modal
contentSnippetCustom content replacing the entire default layout
headerSnippetCustom header section
titleSlotSnippetCustom title content — overrides title prop
descriptionSlotSnippetCustom description content — overrides description prop
bodySnippetMain body content area
footerSnippetFooter area for action buttons
closeSlotSnippetCustom close button — replaces default close icon

Props

PropTypeDefault
openbooleanfalse
onOpenChange(open: boolean) => void-
titlestring-
descriptionstring-
overlaybooleantrue
scrollablebooleanfalse
transitionbooleantrue
fullscreenbooleanfalse
closeboolean | ModalClosePropstrue
dismissiblebooleantrue
trapFocusbooleantrue
preventScrollbooleantrue
portalbooleantrue
classstring-
uiRecord<Slot, Class>-