Modal

A lightweight dialog for short blocking tasks.

VerifiedSince 0.3.4

Usage

Basic

v-model controls visibility, and the footer slot holds the actions.

Loading demo...

Fullscreen Panel

fullscreen fills the visible viewport: the body scrolls, the header and footer stay fixed, and the footer clears the bottom safe area.

<TxModal v-model="previewOpen" fullscreen :title="current?.name">
  <img :src="current.url" alt="">
  <template #footer>
    <TxButton variant="ghost" @click="previewOpen = false">Close</TxButton>
  </template>
</TxModal>

Best Practices

  • Limit a modal to a confirmation, one-step input, or short decision; use a drawer or page for navigation, filtering, or long forms.
  • With a custom header, keep a visible title and leave title empty, or aria-labelledby points at a missing element.
  • Put destructive or final actions in the footer, and keep secondary actions visually quieter than the primary one.
  • Use fullscreen only when the content owns the screen (image or diagram previews), never for a short confirmation.
  • Don't keep long-running async state only inside the modal content; if closing cancels work, model the cancellation in the parent.
  • On non-English surfaces, pass closeLabel: the close button is icon-only, so this name is all a screen reader announces.

API Reference

Props

PropTypeDefaultDescription
modelValuebooleanrequiredWhether the dialog is shown; used by v-model.
titlestring''Default header title; when set, it is linked through aria-labelledby.
widthstring'480px'Panel width; prefer responsive values such as min(92vw, 520px). Ignored with fullscreen.
fullscreenbooleanfalseFills the visible viewport and drops the panel radius and shadow.
closeLabelstring'Close'Accessible name of the header's close button.
surface'pure' | 'mask' | 'blur' | 'glass' | 'refraction' | 'acrylic' | 'mica' | 'flat' | 'plain''refraction'Material of the panel.
surfaceColorstring''Colour laid under the material; follows the theme by default.
surfaceOpacitynumber0.96 for mask, 0.5 otherwiseOpacity of that colour, used by mask, blur, acrylic, glass and refraction; always opaque under pure and flat, and mica and plain lay no base colour.

Events

EventPayloadDescription
update:modelValue(value: boolean)Fires when the component requests a visibility change.
close()Fires after a backdrop click, Escape, or the close button.

Slots

SlotPropsDescription
default-Dialog body.
header-Replaces the title area; the built-in close button stays.
footer-Footer actions; not rendered when omitted.

Overview

  • The overlay teleports to body, takes a fresh layer from the shared z-index manager on open, and is removed with v-if on close.
  • The overlay is role="dialog" with aria-modal="true"; it takes focus on open and returns it to the previous element on close or unmount.
  • Tab and Shift+Tab cycle inside the topmost modal; even with focus on body, a drawer underneath doesn't react to Escape.
  • A backdrop click, Escape, and the close button emit update:modelValue(false), then close.
  • fullscreen changes only the layout, not the dialog semantics or focus handling; it leaves no backdrop to click, so keep a visible close control in the header or footer.
  • The panel background is a card-preset TxBaseSurface (fake) under the header, body and footer, refraction by default: a 50% base colour keeps text legible while the page behind still shows through to be blurred and refracted.
  • The overlay's dim and blur are painted on a pseudo-element of the overlay rather than on its own background and opacity, so the panel's material samples the page, not only the dim.
  • The panel only scales as it opens and closes; it never fades as a whole. Once its opacity animates, every backdrop filter inside it samples nothing but the panel, and the frost would drop out for the whole transition. What fades is each part of the panel instead: the header, body and footer, the shadow and outline, and each layer of the material, so a material with a backdrop filter (such as the default refraction) samples the page from the first frame to the last.
  • TModal forwards props, attrs, events, and the default / header / footer slots to TxModal.

Technologies

  • The fullscreen panel uses a 100dvh height where supported, and its footer padding includes safe-area-inset-bottom; fullscreen drops the overlay's blur, since the panel's own material already covers the viewport.
  • Under reduced motion (prefers-reduced-motion: reduce) the panel fades in place, without scaling or moving.
  • Source: packages/tuffex/packages/components/src/modal/ (TxModal.vue and the TModal.vue wrapper).
查看源码
packages/tuffex/packages/components/src/modal/index.ts