Pricing

Dialog handbook

v1.1.1 · @snowui-design-system/components

License: Before reading component documentation, source, or npm usage instructions for the first time, read the full LICENSE. Reuse that review for the same task and version. Public API configuration and internal implementation changes have different license implications. All components use the unified runtime package; source rights remain governed by the license.

Overview

Present a focused decision or form in a modal layer with title, content, actions, and close behavior.

When to use it

Dialog boxes that require independent focus and close the process. Popover is used for small floating layers to anchor a button, and Tooltip is used for short tips; open combination roles are used for titles and buttons.

  • Use the bind:open control panel; external clicks and Escape are supported by default.

  • By publicizing the title / content / footer / close role combination content; explicit sub-items are self-configured, and parts only affect the default title, separating line and close button.

Quick start

This example shows the recommended basic composition. See the sections below for more cases and composition limits.

<script lang="ts">	import { Dialog, Button, Frame, Text } from '@snowui-design-system/components';	let publishOpen = $state(false);	function setPublishOpen(next: boolean) { publishOpen = next; }</script> <Button variant="filled" onclick={() => publishOpen = true}>Publish documentation</Button><Dialog	open={publishOpen}	onOpenChange={setPublishOpen}	size="md">	<Text as="title" tag="h2">Publish 82 component pages?</Text>	<Frame as="content">This updates the public documentation index and makes every generated example available to visitors.</Frame>	<Frame as="footer">		<Button as="item" variant="outline" data-dialog-close>Cancel</Button>		<Button as="item" variant="filled" onclick={() => publishOpen = false}>Publish</Button>	</Frame></Dialog>

API

Keyword Type Default Description
id string — The unique identification of the template mode
template boolean false Only register the template, not directly displayed.
as "dialog" | undefined — Embedded mode mark
open boolean false The panel mode is hidden and supports bind:open
onOpenChange (open: boolean) => void — Panel mode status change callback
backdrop DialogBackdrop "opaque" Masking layer variant; shared background vision with ImageViewer, shutdown and dynamic effect are still managed by Dialog.
size DialogSize "md" Panel size
closeOnOutside boolean true By default, click the mask outside the panel to close; false is prohibited. The blank space inside the panel is not closed. It is recommended to explicitly set the form to false if the form is not saved or the scene must be clearly selected.
closeOnEscape boolean true Is Escape closed?
pinOffset number — Offset shared by built-in and custom Pins, in px. When omitted, use the token-based default that scales with root font size: 16px for sm/md and 20px for lg.
pinOffsetX number — Cover the horizontal offset of the built-in and external Pin, which takes precedence over pinOffset.
pinOffsetY number — Overlay the vertical offset of built-in and external Pin, giving priority to pinOffset
role "dialog" | string "dialog" The panel can access the role.
title string — Generate a built-in text title; ignore this value when the external as="title" exists
separator boolean — Control the dividing line below the title; do not generate the default behavior when there is no title: sm is false; md/lg is true.
showCloseButton boolean true Whether to display the built-in close button in the upper right corner; do not hide the external close role
closeLabel string locale's closing copy Accessible name with built-in close button
parts ComponentPartsOf<{ Button: typeof Button; Text: typeof Text; Separator: typeof Separator }> — Only configure the actual built-in closed Button, title Text and Separator; it does not affect the explicit components in children/footer; the title id, children and ARIA are owned by Dialog
children Snippet — The content of the dialog box

See the base component documentation for inherited capabilities not redeclared here. This table lists only named public Props declared by this component.

Usage boundaries and details

Three modes (Modes)

Model Writing method Description
Panel mode <Dialog bind:open={state}>...</Dialog> Local status control on and off
Embedded mode <Button>Open <Dialog as="dialog">... </Dialog></Button> Automatically bind the parent element to click to trigger
Template mode <Dialog template id="x">...</Dialog> + showDialog("x") / data-dialog-target="x" Cross-component trigger or multi-trigger sharing

Layout model

Main layout model: composite management layout.

Structure:

Backdrop(portaled to body)└── Container(centered in viewport)    └── Panel Frame(.snowui-dialog .snowui-quick-action-panel)        ├── pin-* slot (optional)        ├── title Text + optional Separator        ├── children body        ├── footer actions        └── built-in close button
  • Padding attribution: Panel is responsible for the overall padding.

  • Gap attribution: Panel has a built-in 12/16/20px spacing of sm/md/lg; 8px in the body and 8/12/12px in the footer.

  • The title is generated by title, and the text is carried by children; the direct as="footer" provides the operation area, and Button as="item" reads the default value of the size of the operation area, and the explicit size takes priority.

  • Pin Attribution: Panel transmission pinOffset / pinOffsetX / pinOffsetY, the default sm/md is 16px and lg is 20px.

  • Scrolling attribution: Panel itself limits max-height, and scrolls inside the panel when the content overflows.

Keywords (Props)

The closing operation of the caller uses the data-dialog-close declaration:

<Button data-dialog-close>Cancel</Button>

Measurement

size max-width padding border-radius gap Title font size/line height Close button / icon / upper right offset Operation area gap / Button size
sm 320px 16px 20px 12px 16/24px,600 24 / 16 / 16px 8px / sm
md 448px 20px 24px 16px 18/28px,600 36 / 20 / 16px 12px / md
lg 640px 24px 28px 20px 18/28px,600 36 / 20 / 20px 12px / md

Geometry and typesetting use rem Token, and the above is the nominal value of the root font size 16px. The title font-weight is 600; the body is unified 14/20px, and 4px text inset is added to the left and right of the title and the body; the close button distance on the panel and the right edge is sm/md 16px, lg 20px. The title is reserved for the close button, and the long title can be replaced.

The close button uses the real Button variant="borderless" iconOnly and ComponentIcon: the color follows the default color of Button, the normal overall opacity is 0.4, hover / focus-visible restore 1; keep the default button hover background, zoom and click feedback. This is the localization of Dialog, which is clearly required by the current task, and does not change the built-in icon host rules of other components. parts.Button only configures the built-in close button, click to close and the accessible name is owned by Dialog. Custom icons are provided with the external as="close" Button; the built-in icon uses IconProvider, and if it is missing, it will be returned to close in the package.

<script lang="ts">  import { Dialog, Text, Frame, Button } from '@snowui-design-system/components';  let open = $state(true);</script> <Dialog bind:open>    <Text as="title" tag="h2">Exit editing</Text>    <Frame as="content">Unsaved changes will be lost.</Frame>    <Frame as="footer">        <Button as="item" variant="outline" data-dialog-close>Cancel</Button>        <Button as="item" variant="filled">Save</Button>    </Frame></Dialog>

Button commands, copywriting, variants and business callbacks are owned by the caller; Dialog only provides the default size value of as="item" through the public Context in the operation area. The non-announced Button keeps its own default, and the explicit size takes precedence. The custom title/close button can be placed in children; the direct close role automatically replaces the built-in close button. When the title is not provided and the built-in close button is turned off, children directly enter the Panel and keep the direct Pin combination; when the title is not provided but the built-in close button is displayed, the top of the text is reserved for the close button space.

Complete role combination

Dialog's external replacement uniformly uses as; title / closeIcon / footer named Snippet replacement entrance is not provided. Ordinary title strings can still generate default titles, and ordinary children can still carry the text.

Role Default and replacement behavior
title Replace the built-in title, ignore the title string and parts.Text; restore the string title after removal. The default title layout and close button avoidance are provided by Dialog, and tags such as tag="h2" are provided by the caller.
separator Replace the default dividing line, ignore the separator switch and parts.Separator; after removal, generate the default dividing line according to the size and separator. The thickness and other direct Props of the external Separator are controlled by the caller.
content The explicit body container provides body typesetting and internal gap; the content and direct style are owned by the caller.
footer The explicit operation area provides the layout and the size Context of the direct item.
close Replace the shutdown button to take over the same shutdown behavior and positioning.

The five characters are all single cases, and only identify the direct elements of the children rendering host; multiple characters of the same name report errors in the development environment, and only the first one is displayed. External instances do not consume parts. The native node uses data-as. The title, dividing line, body and operation area are arranged in order, and the caller should also write in this order to keep the reading consistent with the keyboard order.

When the external title exists, Dialog's aria-labelledby uses its id; it will be automatically replenished when the id is missing, and the automatically generated id will be cleaned when the role is removed, and the caller's own id will be retained. The explicit aria-label / aria-labelledby is prioritized by the caller configuration. The default dividing line is not generated when there is no title.

<script lang="ts">  import { Dialog, Text, Separator, Frame, Button } from '@snowui-design-system/components';  let open = $state(true);</script> <Dialog bind:open>    <Text as="title" tag="h2">Exit editing <Text>Additional information</Text></Text>    <Separator as="separator" />    <Frame as="content">Unsaved changes will be lost.</Frame>    <Frame as="footer">        <Button as="item" variant="outline" data-dialog-close>Cancel</Button>        <Button as="item" variant="filled">Save</Button>    </Frame>    <Button as="close" variant="borderless" iconOnly size="md" aria-label="Close">        Close    </Button></Dialog>

The role of the bottom operation area

Declare the action area as a direct <Frame as="footer"> child, or use data-as="footer" on a native element. Dialog supplies right alignment, vertical centering, wrapping, and preferred sm/md/lg gaps of 8/12/12px. Keep at least 4 CSS px between actions; larger --snowui-dialog-footer-gap-override values remain effective. Direct Props and inline styles can override the layout and do not consume parts. The footer and body blocks retain the panel gap of 12/16/20px; wrap multiple body blocks in a separate container when an internal 8px gap is needed.

Only the direct Button as="item" of the operation area receives sm/md/md size Context, and the explicit size takes priority; the button content, variant, business events and nested layout are still owned by the caller. The item in the text and nested Frame that has not been contracted does not receive this default value.

The footer is a single case, the identification range is the same as close, and the nested container is not scanned. Multiple direct footers reported errors in the development environment, and only the first one was displayed. No empty operation area will be generated after removing the footer. The button behavior is always generated by the real button, and the role itself does not inject confirmation or cancellation events.

External shutdown button replacement

A direct child with as="close" (rendered as data-as="close") replaces the built-in close button automatically; no showCloseButton={false} or data-dialog-close is needed. It shares the built-in button’s panel anchor and pinOffsetX/pinOffsetY. The internal text wrapper only handles typography. Detection examines direct elements in the children host, not descendants nested inside Frame, footer, or title.

<Dialog title="Custom content">    <Button as="close" variant="borderless" iconOnly size="md" aria-label="Close">        <Close size={20} />    </Button>    Body content</Dialog>

The variant, size, color, opacity, Icon and accessible name of the external button are directly configured by the caller and do not inherit parts.Button; Dialog only has role positioning, replacement and shutdown behaviors. The external button click or keyboard activation goes to the same close link, and the event preventDefault() can prevent the role from closing. Disabled / aria-disabled="true" is not closed. The external role takes precedence over showCloseButton; after removing the external role, press the showCloseButton to restore the built-in button. Nested characters of the same name do not participate in replacement.

This role is a single case: multiple direct external roles report errors in the development environment, and only the first one is displayed and used in production. Icons are also provided through the sub-content in this role.

Backdrop

Variation Vision
opaque 10% black mask
blur 10% black mask + 20px background blur
transparent Transparent mask, only blocking background interaction

When opaque and blur are mounted, they gradually enter from opacity 0 to the set mask effect; when they are closed, they gradually exit, and when they are closed, they are reopened from the current transparency. The duration and curve use Dialog backdrop preset; reduce the direct display or hide under the dynamic preference, and do not play the transparency transition.

Barrier-free

  • role="dialog"

  • aria-modal="true"

  • When opened, the focus enters the first focusable element in the Dialog.

  • Tab / Shift+Tab loops in the Dialog.

  • When closed, the focus returns to the trigger element. The inline mode will locate the actual interaction host through the content wrapping layer of the Button, and return the focus to the button or link after closing.


Dialog style overlay

Read the full LICENSE first; reuse that review for the same task, version, and scope.

First use public component Props to match the desired appearance, preserving the existing look where possible. If changes are necessary, follow the style selection and override order: use your own class (including Tailwind already in the project) or an instance style. The names below are public overrides actually consumed by source; check their scope and do not modify private DOM. Choose the correct SnowUI token family. External apps need not install SnowUI website utilities.

Variable Purpose and default reference
--snowui-button-opacity-override Opacity (see the component source code for the default value)
--snowui-dialog-font-size-override Font-size (default var(--text-14)=14px)
--snowui-dialog-line-height-override Line-height (default var(--leading-14)=20px)
--snowui-dialog-max-width-override Max-width (default sm=320px md=448px lg=640px)
--snowui-dialog-padding-override Padding (default sm var(--padding-4)=16px; md/lg var(--padding-6)=24px)
--snowui-dialog-radius-override Border-radius (default sm var(--radius-6)=24px; md/lg calc(var(--radius-4)*2)=32px)

Design Guide · Token · Combination Boundary

Dialog type and status

Required Props: no named required Props.

Two-way binding: bind:open.

Inheritance statement: Omit<FrameProps, "children" | "as" | "title">. The inheritance ability is subject to the public document of the base class; the fields in Omit have been excluded and cannot be used as they are according to the base class.

Share Frame API · Return API

The following type declarations are actually referenced by public Props and come from source. A Svelte Snippet denotes a content fragment; ComponentProps denotes the Props of the corresponding component.

DialogBackdrop

Source: components/src/logic/dialog.svelte.ts

export type DialogBackdrop = import("../lib/backdrop").BackdropVariant;

DialogSize

Source: components/src/logic/dialog.svelte.ts

export type DialogSize = "sm" | "md" | "lg";

ComponentPartsOf

Source: components/src/logic/component-parts.svelte.ts

export type ComponentPartsOf<    T extends Record<string, Component<any>>,> = {    [K in keyof T]?: ConfigurableComponentPartProps<T[K]>;};

ConfigurableComponentPartProps

Source: components/src/logic/component-parts.svelte.ts

export type ConfigurableComponentPartProps<C extends Component<any>> = Partial<    Omit<ComponentProps<C>, ComponentPartControlledKey>>;

ComponentPartControlledKey

Source: components/src/logic/component-parts.svelte.ts

export type ComponentPartControlledKey =    | "children"    | "as"    | "value"    | "defaultValue"    | "open"    | "selected"    | "checked"    | "disabled"    | "readonly"    | "id"    | `on${string}`    | `aria-${string}`;