Moodinary/UI

Dialog

Tareas cortas que no justifican una página (crear acción, invitar). Esc cierra, Tab queda adentro.

Modal sobre @base-ui/react/dialog para tareas cortas que no justifican una página, como crear un equipo o invitar a alguien. Las confirmaciones destructivas de la app usan ConfirmDialog.

Instalación

shadcn
npx shadcn@latest add https://design.moodinary.com/r/dialog.json
import
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@moodinary/ui/components/dialog";

Ejemplos

Nuevo equipo

Título, una línea de contexto, los campos justos y el footer con Cancelar y el primario a la derecha.

Código
new-action.tsx
import { Button } from "@moodinary/ui/components/button";
import {
	Dialog,
	DialogContent,
	DialogDescription,
	DialogFooter,
	DialogHeader,
	DialogTitle,
} from "@moodinary/ui/components/dialog";
import { Input } from "@moodinary/ui/components/input";
import { Label } from "@moodinary/ui/components/label";
import { useCallback, useState } from "react";

export default function CreateTeam() {
	const [open, setOpen] = useState(false);
	const [name, setName] = useState("");
	const close = useCallback(() => setOpen(false), []);
	const show = useCallback(() => setOpen(true), []);
	const submit = useCallback(
		(event: React.FormEvent) => {
			event.preventDefault();
			setName("");
			close();
		},
		[close]
	);
	return (
		<>
			<Button onClick={show}>Nuevo equipo</Button>
			<Dialog onOpenChange={setOpen} open={open}>
				<DialogContent>
					<DialogHeader>
						<DialogTitle>Nuevo equipo</DialogTitle>
						<DialogDescription>
							Los equipos agrupan miembros para capturar pulsos con contexto
							(área, proyecto, sede).
						</DialogDescription>
					</DialogHeader>
					<form className="space-y-4" onSubmit={submit}>
						<div className="space-y-2">
							<Label htmlFor="team-name">Nombre</Label>
							<Input
								autoFocus
								id="team-name"
								maxLength={80}
								onChange={(event) => setName(event.target.value)}
								placeholder="Equipo A"
								required
								value={name}
							/>
						</div>
						<DialogFooter>
							<Button onClick={close} type="button" variant="secondary">
								Cancelar
							</Button>
							<Button disabled={!name.trim()} type="submit">
								Crear equipo
							</Button>
						</DialogFooter>
					</form>
				</DialogContent>
			</Dialog>
		</>
	);
}

Props

Dialog

PropTipoDefaultDescripción
openboolean-Estado controlado.
defaultOpenbooleanfalseEstado inicial sin controlar.
onOpenChange(open: boolean) => void-Se llama al abrir o cerrar.
modalboolean | "trap-focus"trueBloquea el resto de la página.

DialogContent

PropTipoDefaultDescripción
showCloseButtonbooleantrueMuestra la X arriba a la derecha.
classNamestring-Clases extra. El ancho máximo es 440 px.

Cuándo sí y cuándo no

Hacé
  • Usá un título que diga la tarea: Nueva acción.
  • Mantené el formulario en dos o tres campos.
  • Poné el primario a la derecha del footer.
Evitá
  • No abras un dialog desde otro dialog.
  • No lo uses para confirmar borrados; la app usa ConfirmDialog.
  • No metas tablas largas ni flujos de varios pasos.

Accesibilidad

  • Esc cierra y el foco queda atrapado adentro mientras está abierto.
  • Al cerrar, el foco vuelve al botón que lo abrió.
  • El título se conecta con aria-labelledby solo.