Recipeoverlay

Dialog Stack

Stable

Fluxo de várias etapas apresentado como uma pilha de cartas: a etapa ativa é o painel da frente e as anteriores ficam como bordas acima dele. É um único dialog com várias etapas, não vários dialogs — o primitive Dialog (Base UI) é dono de modalidade, portal, overlay, foco, Escape, descarte e estado de abertura, e a recipe é dona do workflow. Apenas a etapa ativa monta conteúdo, então não sobram títulos duplicados nem campos focáveis invisíveis atrás dela.

Instalação

npx up-web-ds add dialog-stack

Preview

Basic

With Fields

Six Steps

Clickable Navigation

Disable Overlay Close

Controlled

aberto: false · onOpenChange: 0

All states

Basic

With Fields

Six Steps

Clickable Navigation

Disable Overlay Close

Controlled

aberto: false · onOpenChange: 0

Usage

Imports de Dialog Stack
import {
  DialogStack,
  DialogStackBody,
  DialogStackContent,
  DialogStackDescription,
  DialogStackFooter,
  DialogStackHeader,
  DialogStackNext,
  DialogStackPrevious,
  DialogStackTitle,
  DialogStackTrigger,
} from '@/components/ui/dialog-stack'
import { Button } from '@/components/ui/button'
Dialog Stack
<DialogStack>
  <DialogStackTrigger render={<Button variant="outline" />}>
    Ingerir componente
  </DialogStackTrigger>

  <DialogStackBody>
    <DialogStackContent>
      <DialogStackHeader>
        <DialogStackTitle>Identificar a fonte</DialogStackTitle>
        <DialogStackDescription>
          Registry público, template pago ou código de um projeto interno.
        </DialogStackDescription>
      </DialogStackHeader>

      <DialogStackFooter>
        <DialogStackPrevious>Anterior</DialogStackPrevious>
        <DialogStackNext variant="primary">Próximo</DialogStackNext>
      </DialogStackFooter>
    </DialogStackContent>

    <DialogStackContent>
      <DialogStackHeader>
        <DialogStackTitle>Revisar a licença</DialogStackTitle>
        <DialogStackDescription>
          Uso em produto final não é licença para redistribuir por registry.
        </DialogStackDescription>
      </DialogStackHeader>

      <DialogStackFooter>
        <DialogStackPrevious>Anterior</DialogStackPrevious>
        <DialogStackNext variant="primary">Próximo</DialogStackNext>
      </DialogStackFooter>
    </DialogStackContent>

    <DialogStackContent>
      <DialogStackHeader>
        <DialogStackTitle>Classificar o item</DialogStackTitle>
        <DialogStackDescription>
          Primitive, recipe, component, pattern, block ou template.
        </DialogStackDescription>
      </DialogStackHeader>

      <DialogStackFooter>
        <DialogStackPrevious>Anterior</DialogStackPrevious>
        <DialogStackNext variant="primary">Concluir</DialogStackNext>
      </DialogStackFooter>
    </DialogStackContent>
  </DialogStackBody>
</DialogStack>

Props

DialogStack

Props de DialogStack
PropTypeDefaultDescription
clickablebooleanfalseWhether the card edges behind the active step navigate back to it.
defaultOpenbooleanfalseOpen state for an uncontrolled stack.
disableOverlayClosebooleanfalseLocks dismissal to the dialog's own close actions: a press on the overlay and the Escape key no longer close it, only a `DialogClose` (the footer's Cancelar, the popup's close button) or a controlled `open` does. For a dialog whose content would be lost if it closed by accident, such as a half-filled form.
onOpenChange((open: boolean) => void)sem valor padrãoCalled once per real change of the open state.
openbooleansem valor padrãoOpen state, controlled.

Estende React.ComponentProps<'div'> & Pick<DialogProps, 'disableOverlayClose'>. Aceita também os atributos padrão de um elemento React (280 não listados).

DialogStackTrigger

Props de DialogStackTrigger
PropTypeDefaultDescription
asChilddeprecatedbooleansem valor padrãoRadix's composition escape hatch, kept for upstream compatibility.
classNamestring | ((state: DialogTriggerState) => string | undefined)sem valor padrãoCSS class applied to the element, or a function that returns a class based on the component's state.
handleDialogHandle<unknown>sem valor padrãoA handle to associate the trigger with a dialog. Can be created with the Dialog.createHandle() method.
idstringsem valor padrãoID of the trigger. In addition to being forwarded to the rendered element, it is also used to specify the active trigger for the dialog in controlled mode (with the DialogRoot `triggerId` prop).
nativeButtonbooleantrueWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).
payloadunknownsem valor padrãoA payload to pass to the dialog when it is opened.
renderReact.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTriggerState>sem valor padrãoAllows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
styleReact.CSSProperties | ((state: DialogTriggerState) => React.CSSProperties | undefined)sem valor padrãoStyle applied to the element, or a function that returns a style object based on the component's state.

Estende React.ComponentProps< typeof DialogTrigger >. Aceita também os atributos padrão de um elemento React (284 não listados).

DialogStackOverlay

Estende React.ComponentProps<'div'>. Aceita também os atributos padrão de um elemento React (280 não listados).

DialogStackBody

Props de DialogStackBody
PropTypeDefaultDescription
equalHeightbooleantrueWhether every step takes the height of the tallest one. A stack whose panel changes height on every step moves its own card edges, and — centred in the viewport — the whole stack with them, so the piling-up the recipe is named after reads as jitter. With this on, the panel keeps one height for the whole workflow, and a shorter step's footer stays pinned to the bottom of it. The height is measured, not guessed: every step is rendered once into an invisible, inert layer, sized, and taken away again before the browser paints. It is measured again when the panel changes width, because the text wraps differently. A step that grows while it is on screen still grows: this is a floor, not a clamp.
overlayClassNamestringsem valor padrãoPresentation classes for the scrim behind the stack.
showCloseButtonbooleantrueWhether the active step shows the Dialog's close affordance. Upstream has no way out other than the scrim. Base UI asks for a `Dialog.Close` inside a modal popup so a touch screen reader can escape it, so this defaults to on.

Estende React.ComponentProps<'div'>. Aceita também os atributos padrão de um elemento React (280 não listados).

DialogStackContent

Props de DialogStackContent
PropTypeDefaultDescription
indexnumbersem valor padrãoThe position of this step. `DialogStackBody` assigns it; passing it is only useful for a step rendered outside a body.
offsetnumber10Distance in pixels between this step's card edge and the next one.

Estende React.ComponentProps<'div'>. Aceita também os atributos padrão de um elemento React (280 não listados).

DialogStackHeader

Estende React.ComponentProps<typeof DialogHeader>. Aceita também os atributos padrão de um elemento React (280 não listados).

DialogStackTitle

Props de DialogStackTitle
PropTypeDefaultDescription
classNamestring | ((state: DialogTitleState) => string | undefined)sem valor padrãoCSS class applied to the element, or a function that returns a class based on the component's state.
renderReact.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTitleState>sem valor padrãoAllows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
styleReact.CSSProperties | ((state: DialogTitleState) => React.CSSProperties | undefined)sem valor padrãoStyle applied to the element, or a function that returns a style object based on the component's state.

Estende React.ComponentProps<typeof DialogTitle>. Aceita também os atributos padrão de um elemento React (275 não listados).

DialogStackDescription

Props de DialogStackDescription
PropTypeDefaultDescription
classNamestring | ((state: DialogDescriptionState) => string | undefined)sem valor padrãoCSS class applied to the element, or a function that returns a class based on the component's state.
renderReact.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogDescriptionState>sem valor padrãoAllows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
styleReact.CSSProperties | ((state: DialogDescriptionState) => React.CSSProperties | undefined)sem valor padrãoStyle applied to the element, or a function that returns a style object based on the component's state.

Estende React.ComponentProps< typeof DialogDescription >. Aceita também os atributos padrão de um elemento React (275 não listados).

DialogStackNext

Props de DialogStackNext
PropTypeDefaultDescription
asChilddeprecatedbooleansem valor padrãoRadix's composition escape hatch, kept for upstream compatibility.
size"default" | "sm" | "xs" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | nullsem valor padrão
variant"link" | "destructive" | "primary" | "outline" | "secondary" | "ghost" | nullsem valor padrão
classNamestring | ((state: ButtonState) => string | undefined)sem valor padrãoCSS class applied to the element, or a function that returns a class based on the component's state.
focusableWhenDisabledbooleanfalseWhether the button should be focusable when disabled.
nativeButtonbooleantrueWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).
renderReact.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, ButtonState>sem valor padrãoAllows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
styleReact.CSSProperties | ((state: ButtonState) => React.CSSProperties | undefined)sem valor padrãoStyle applied to the element, or a function that returns a style object based on the component's state.

Estende StepButtonProps. Aceita também os atributos padrão de um elemento React (285 não listados).

DialogStackPrevious

Props de DialogStackPrevious
PropTypeDefaultDescription
asChilddeprecatedbooleansem valor padrãoRadix's composition escape hatch, kept for upstream compatibility.
size"default" | "sm" | "xs" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | nullsem valor padrão
variant"link" | "destructive" | "primary" | "outline" | "secondary" | "ghost" | nullsem valor padrão
classNamestring | ((state: ButtonState) => string | undefined)sem valor padrãoCSS class applied to the element, or a function that returns a class based on the component's state.
focusableWhenDisabledbooleanfalseWhether the button should be focusable when disabled.
nativeButtonbooleantrueWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).
renderReact.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, ButtonState>sem valor padrãoAllows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
styleReact.CSSProperties | ((state: ButtonState) => React.CSSProperties | undefined)sem valor padrãoStyle applied to the element, or a function that returns a style object based on the component's state.

Estende StepButtonProps. Aceita também os atributos padrão de um elemento React (285 não listados).

Composition

O gatilho e o corpo são irmãos dentro do DialogStack. Cada filho do DialogStackBody é uma etapa, na ordem em que aparece; só a ativa renderiza.

Composição de DialogStack

DialogStack

  • DialogStackTrigger
  • DialogStackBody
    • DialogStackContent
      • DialogStackHeader
        • DialogStackTitle
        • DialogStackDescription
      • DialogStackFooter
        • DialogStackPrevious
        • DialogStackNext

Metadata

Notas de acessibilidade

Teclado e leitor de tela verificados por teste (Vitest) e em navegador (tests/e2e/dialog-stack.spec.ts, Chromium desktop e mobile, light e dark). Abre pelo gatilho e pelo teclado; fecha por Escape, pelo DialogClose e por pressão fora. O foco entra na etapa ativa ao abrir, fica preso enquanto está aberta — medido no navegador, porque o jsdom não implementa `inert` —, permanece dentro do dialog na troca de etapa e volta ao gatilho ao fechar. Existe exatamente um `role="dialog"`, um `dialog-title` e um conteúdo de etapa em qualquer passo, nomeado e descrito pela etapa atual: etapas anteriores e futuras não deixam heading, descrição, campo nem botão no documento. Sem `clickable`, as bordas da pilha são `aria-hidden` e ficam fora da árvore de acessibilidade; com `clickable`, cada uma é um `<button type="button">` nomeado (“Voltar para a etapa N”), dentro do popup e portanto ao alcance do teclado. Axe sem violações WCAG 2.2 AA com a pilha aberta, em light e dark. Toque verificado em viewport de 375px com emulação de toque: com `clickable`, a faixa exposta de cada borda tem piso de 24px (`MIN_TARGET`), acima do mínimo de 24x24 da WCAG 2.2 SC 2.5.8 — o upstream expõe 10px, e essa é uma diferença deliberada que vale só no modo interativo; a pilha decorativa mantém o espaçamento do upstream. Reduced motion verificado em navegador com prefers-reduced-motion: reduce: `motion-reduce:transition-none` remove o tween das bordas e elas já aparecem na profundidade nova; a animação de entrada e saída do popup não é condicionada, porque é o `animationend` dela que o Base UI espera para desmontar, e o descarte continua funcionando. Na troca de etapa, o conteúdo entra com fade e um deslocamento de 0,5rem conforme a direção (de baixo ao avançar, de cima ao voltar) e a borda da etapa deixada para trás cresce a partir do topo do painel; sob reduce, o deslocamento é condicionado a `motion-safe:` e some, o fade permanece encurtado para `duration-fast`, e o crescimento da borda lê a duração da transição dela, que é `none`, e não toca. Todas as etapas têm a altura da maior (`equalHeight`, padrão ligado), medida numa camada invisível, `inert` e `aria-hidden` que existe só durante um layout e é removida antes do paint, então o painel e a pilha não se deslocam entre etapas.

Classificação

Layer
Recipe
Domínio
Domain-free (compartilhado)
Categoria
overlay
Status
Stable

Origem e distribuição

Fonte
kibo registry / dialog-stack
Licença
MIT
Distribuição
Interna

Acessibilidade

  • Teclado: revisado
  • Leitor de tela: revisado
  • Touch: revisado
  • Reduced motion: revisado

Dependências

Pacotes
Nenhuma
Ícones
Nenhum
Construído sobre
DialogButton
Usado por
Nenhum ainda