Skip to content
UI
v0.3.1

Search the docs

Modal

A dialog that needs an answer before going on.

Example

Close this round?

The player gets their win and the round cannot be reopened.

modal.example.svelte
<script lang="ts">
  import { Button, Modal } from '@onlywin/ui-svelte';

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

<Button variant="danger" onclick={() => (open = true)}>Close round</Button>
<Modal
  bind:open
  title="Close this round?"
  description="The player gets their win and the round cannot be reopened."
>
  {#snippet footer()}
    <Button variant="ghost" onclick={() => (open = false)}>Cancel</Button>
    <Button variant="danger" onclick={() => (open = false)}>Close round</Button>
  {/snippet}
</Modal>

Usage

Do

  • Ask one question; name the buttons after their actions.

Don’t

  • Do not open a modal from a modal.

Accessibility

  • A native modal <dialog>: focus moves in and stays, the page behind is inert, the title names it.
  • Escape, the close button and a click on the backdrop close it, unless dismissible is false.

Keyboard

Modal keyboard interactions
Keys Action
Escape Close
Tab, Shift+Tab Move focus inside

Props

The same props in both frameworks. In React, class is className, events are camelCase (onClick), content passed as Svelte snippets is a ReactNode prop, every bindable value has a default… twin for uncontrolled use, and elementRef reaches the DOM element.

Modal props
Prop Type Default Description
children Snippet —
description string —
dismissible boolean true
footer Snippet — Buttons under the body, right-aligned.
onOpenChange (open: boolean) => void —
open boolean false Bindable in Svelte; defaultOpen in React.
size 'lg' | 'md' | 'sm' 'md'
title *required string —