Modal
A lightweight dialog for short blocking tasks.
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 leavetitleempty, oraria-labelledbypoints at a missing element. - Put destructive or final actions in the
footer, and keep secondary actions visually quieter than the primary one. - Use
fullscreenonly 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
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | boolean | required | Whether the dialog is shown; used by v-model. |
title | string | '' | Default header title; when set, it is linked through aria-labelledby. |
width | string | '480px' | Panel width; prefer responsive values such as min(92vw, 520px). Ignored with fullscreen. |
fullscreen | boolean | false | Fills the visible viewport and drops the panel radius and shadow. |
closeLabel | string | 'Close' | Accessible name of the header's close button. |
surface | 'pure' | 'mask' | 'blur' | 'glass' | 'refraction' | 'acrylic' | 'mica' | 'flat' | 'plain' | 'refraction' | Material of the panel. |
surfaceColor | string | '' | Colour laid under the material; follows the theme by default. |
surfaceOpacity | number | 0.96 for mask, 0.5 otherwise | Opacity 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
| Event | Payload | Description |
|---|---|---|
update:modelValue | (value: boolean) | Fires when the component requests a visibility change. |
close | () | Fires after a backdrop click, Escape, or the close button. |
Slots
| Slot | Props | Description |
|---|---|---|
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 withv-ifon close. - The overlay is
role="dialog"witharia-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), thenclose. fullscreenchanges 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,refractionby 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. TModalforwards props, attrs, events, and thedefault/header/footerslots toTxModal.
Technologies
- The fullscreen panel uses a
100dvhheight where supported, and its footer padding includessafe-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.vueand theTModal.vuewrapper).
查看源码
packages/tuffex/packages/components/src/modal/index.ts