Components

Dialog

Source
Headless modal and non-modal dialog primitive covering trigger, portal, overlay, and content with full dismiss behavior.

Overview

Dialog is a headless @vyui/core primitive for an overlay window layered above the page. It ships behavior only: open/close state, portalling, overlay, and dismissal, and it leaves all markup and styling to you. The styled Modal component in @vyui/kit is built on top of it.

This is a layer of @vyui/core. If you want a drop-in styled dialog, reach for VyModal in @vyui/kit instead and only compose these primitives when you need full control.

Anatomy

<DialogRoot>
  <DialogTrigger />
  <DialogPortal>
    <DialogOverlay />
    <DialogContent>
      <DialogTitle />
      <DialogDescription />
      <DialogClose />
    </DialogContent>
  </DialogPortal>
</DialogRoot>

Usage

<script setup lang="ts">
import {
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogOverlay,
  DialogPortal,
  DialogRoot,
  DialogTitle,
  DialogTrigger,
} from '@vyui/core'

const open = ref(false)
</script>

<template>
  <DialogRoot v-model:open="open">
    <DialogTrigger>
      <text>Open dialog</text>
    </DialogTrigger>

    <DialogPortal>
      <DialogOverlay />
      <DialogContent>
        <DialogTitle>
          <text>Confirm changes</text>
        </DialogTitle>
        <DialogDescription>
          <text>This updates your workspace settings.</text>
        </DialogDescription>
        <DialogClose>
          <text>Close</text>
        </DialogClose>
      </DialogContent>
    </DialogPortal>
  </DialogRoot>
</template>

Features and behavior

  • modal defaults to true; interaction with content behind the overlay is blocked and assistive tech is confined to the dialog. Set modal="false" for a non-modal dialog that leaves the rest of the page interactive and reachable.
  • open / v-model:open controls visibility; defaultOpen seeds uncontrolled state.
  • DialogContent traps focus while open and restores it to the trigger on close.
  • DialogClose and pressing dismiss/back close the dialog and emit update:open.
  • DialogPortal renders the overlay and content at the root of the tree so they layer above sibling content.

API

DialogRoot

PropDefaultType
defaultOpenfalseboolean | undefined

The open state of the dialog when it is initially rendered. Use when you do not need to control its open state.

modaltrueboolean | undefined

The modality of the dialog. When `true`, `DialogOverlay` paints its tap-blocking backdrop and the content confines assistive tech via `exclusiveFocus`.

openundefinedboolean | undefined

The controlled open state of the dialog. Can be bound as `v-model:open`.

EventPayload
update:open[value: boolean]

DialogTrigger

PropDefaultType
as"view"AsTag | Component | undefined

The element or component this component should render as. Can be overwritten by `asChild`.

asChildboolean | undefined

Render through the passed child element instead of the default one, merging their props and behavior while keeping the primitive's.

DialogContent

PropDefaultType
asAsTag | Component | undefined

The element or component this component should render as. Can be overwritten by `asChild`.

asChildboolean | undefined

Render through the passed child element instead of the default one, merging their props and behavior while keeping the primitive's.

backdropClassstring | undefined

Class merged onto the full-screen backdrop wrapper (the `OverlayBackdrop` that centers the panel). Core ships no dim or animation of its own; the element carries the Presence lifecycle classes and `bindanimation*` hooks, so the styled layer's keyframes drive the lifecycle just like the panel's.

backdropStyleRecord<string, any> | undefined

Style applied to the full-screen backdrop wrapper. No defaults — pass `backgroundColor`, alignment, etc. here for the modal dim/centering.

debugLogboolean | undefined

Verbose lifecycle tracing — forwarded to both backdrop + panel Presence.

transitionboolean | undefined

Opt the backdrop / panel into the animating-state classes (`ui-entering` / `ui-leaving` / `ui-animating` alongside `ui-open` / `ui-closed`). Off for callers that don't style transitions.

EventPayload
interactOutside[event: DismissableLayerEvent]
pointerDownOutside[event: DismissableLayerEvent]

DialogOverlay

PropDefaultType
asAsTag | Component | undefined

The element or component this component should render as. Can be overwritten by `asChild`.

asChildboolean | undefined

Render through the passed child element instead of the default one, merging their props and behavior while keeping the primitive's.

DialogClose

PropDefaultType
as"view"AsTag | Component | undefined

The element or component this component should render as. Can be overwritten by `asChild`.

asChildboolean | undefined

Render through the passed child element instead of the default one, merging their props and behavior while keeping the primitive's.

Accessibility

  • DialogContent exposes native Lynx dialog semantics; always include a DialogTitle so the dialog is announced.
  • DialogDescription is associated with the content as its accessible description.
  • Lynx has no DOM focus model, so the primitive does not trap focus or restore it to the trigger on close.
  • Modal is the styled @vyui/kit dialog built on this primitive.
  • AlertDialog is this primitive with role="alertdialog" preset — undismissable, with required action/cancel.
  • Sheet is a drag-snappable bottom sheet alternative.