Skip to content
portalbits
Home Docs GitHub(opens in a new tab)

Guides

Get startedFoundationsMotion

Components

All components

Buttons

ButtonIconButton

Inputs

InputSelectTextareaSlider

Selection

CheckboxToggleToggleGroupSwitchRadioGroup

Identity

AvatarBadge

Overlays

DialogPopoverTooltipDropdownMenuAlertDialog

Disclosure

TabsAccordion

Cards

AppCardArticleCardFeatureCard

Content

CarouselSectionHeaderEmptyStateAlertProgressSeparatorRowListRow

Chrome

PortalShellSidebarNavMobileNavTopBarAuthFrameColorSelectorFloatingNav

Dialog

A focused panel with a title, Escape, and focus restoration.

Try Tab, Escape, and clicking outside.

Variations
More examples

Icon trigger

An icon-only trigger takes its name from triggerLabel.

Source

<script lang="ts">
  import 'portal-bits/styles.css';
  import 'portal-bits/tokens.css';
  import type { Snippet } from 'svelte';

  let { children }: { children: Snippet } = $props();
</script>

{@render children()}
<script lang="ts">
  import DialogExample from './DialogExample.svelte';
</script>

<DialogExample description={true} />
<script lang="ts">
  import { Alert, Button, Dialog, Input } from 'portal-bits';
  let { description = true }: { description?: boolean } = $props();
  let open = $state(false);
  let name = $state('Alex Morgan');
  let saved = $state(false);
  let error = $state('');

  function save(event: SubmitEvent) {
    event.preventDefault();
    if (!name.trim()) {
      error = 'Enter a display name.';
      return;
    }
    error = '';
    saved = true;
    open = false;
  }
</script>

<div class="stack">
  <Dialog
    title="Make yourself at home"
    description={description ? 'Edit your display name. This example stays in your browser.' : ''}
    bind:open
  >
    {#snippet trigger()}
      Edit profile
      <svg
        width="15"
        height="15"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
        aria-hidden="true"><path d="M7 7h10v10" /><path d="M7 17 17 7" /></svg
      >
    {/snippet}
    <form onsubmit={save}>
      <Input
        label="Display name"
        bind:value={name}
        invalid={!!error}
        aria-describedby={error ? 'name-error' : undefined}
      />
      {#if error}<Alert id="name-error" message={error} />{/if}
      <div class="actions">
        <span>Local demo only</span>
        <Button variant="green" type="submit">Save profile</Button>
      </div>
    </form>
  </Dialog>
  <p aria-live="polite">
    {saved ? `Profile saved as ${name}.` : 'Try Tab, Escape, and clicking outside.'}
  </p>
</div>

<style>
  .stack {
    display: grid;
    justify-items: center;
    gap: 12px;
  }
  p {
    margin: 0;
  }
  .actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 24px;
    color: var(--portal-muted);
    font-size: 14px;
  }
</style>

API reference

These tables list the props and snippets that Dialog declares. Attributes passed through to an element or primitive are listed under Forwarded attributes, not here.

Props

NameTypeDefaultRequiredBindingDescription
openbooleanfalseNoBindableWhether the dialog is open.
titlestringNoneYesOne-wayThe dialog heading. It names the dialog.
descriptionstring""NoOne-waySupporting text under the heading. It is omitted when empty.
triggerLabelstringNoneNoOne-waySets `aria-label` on the trigger. Use it when the trigger content is an icon.
triggerClassstringSecondary 40px buttonNoOne-wayReplaces the trigger classes. The default is a secondary 40px button.
theme'light' | 'dark'lightNoOne-wayTheme scope for the portaled content. Portaled content does not inherit the page scope.

Snippets

NameTypeDefaultRequiredBindingDescription
triggerSnippetNoneNoOne-wayThe trigger content. Without it, no trigger renders; bind `open`.
childrenSnippetNoneNoOne-wayThe dialog body.

Forwarded attributes

None. Dialog forwards no attributes.

The primitive underneath is a Bits UI peer dependency. Its own options are documented in the Bits UI Dialog documentation. Only the props listed on this page are part of the Dialog contract. No data attributes are documented as stable.

Limits

  • Only `open` of Bits UI `Dialog.Root` is wrapped. Its other options and callbacks are not exposed.
  • The close button is always present and named "Close dialog".
  • `triggerLabel` replaces the visible trigger text as the accessible name.

Related

  • Popover
  • Tooltip
Previous Badge Next Popover

On this page

  • Preview
  • Source
  • API reference
  • Props
  • Snippets
  • Forwarded attributes
  • Limits