Moodinary/UI

Drawer / sheet

Detalle al costado sin perder contexto (detalle de un equipo). En mobile, desde abajo.

Panel lateral usado por la app para editar conectores. El contenido ocupa todo el ancho en mobile y hasta 448 px en escritorio. El borde inferior es una variante disponible, no un flujo actual de la app.

Instalación

shadcn
npx shadcn@latest add https://design.moodinary.com/r/sheet.json
import
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from "@moodinary/ui/components/sheet";

Ejemplos

Conector a la derecha

Patrón del conector real: encabezado con estado, ajustes que scrollean y acciones abajo. Datos ilustrativos.

Código
team-detail.tsx
import { Button } from "@moodinary/ui/components/button";
import { Field, FieldHint, FieldLabel } from "@moodinary/ui/components/field";
import { Input } from "@moodinary/ui/components/input";
import {
	Sheet,
	SheetContent,
	SheetDescription,
	SheetFooter,
	SheetHeader,
	SheetTitle,
	SheetTrigger,
} from "@moodinary/ui/components/sheet";

export default function ConnectorSheet() {
	return (
		<Sheet>
			<SheetTrigger render={<Button variant="secondary" />}>
				Ver conector
			</SheetTrigger>
			<SheetContent className="flex w-full flex-col data-[side=right]:w-full sm:max-w-md">
				<SheetHeader className="flex-row items-center gap-3 border-b">
					<span
						aria-hidden
						className="grid size-10 shrink-0 place-items-center rounded-lg border bg-background"
					>
						↗
					</span>
					<div className="min-w-0">
						<SheetTitle className="truncate">Avisos del equipo</SheetTitle>
						<SheetDescription>Webhook · activo</SheetDescription>
					</div>
				</SheetHeader>
				<div className="flex-1 space-y-6 overflow-y-auto p-4">
					<section className="space-y-3">
						<h3 className="font-medium text-sm">Ajustes</h3>
						<Field>
							<FieldLabel htmlFor="cn-name">Nombre</FieldLabel>
							<Input defaultValue="Avisos del equipo" id="cn-name" />
						</Field>
						<Field>
							<FieldLabel htmlFor="cn-url">URL</FieldLabel>
							<Input
								className="font-mono text-xs"
								id="cn-url"
								placeholder="https://ejemplo.com/eventos"
							/>
							<FieldHint>Dejalo vacío para mantener la actual.</FieldHint>
						</Field>
					</section>
					<section className="space-y-2 border-t pt-4">
						<h3 className="font-medium text-sm">Últimos envíos</h3>
						<p className="text-muted-foreground text-sm">
							Todavía no mandamos nada. Probalo para ver si llega.
						</p>
					</section>
				</div>
				<SheetFooter className="flex-row flex-wrap items-center gap-2 border-t">
					<Button variant="primary">Guardar</Button>
					<Button variant="outline">Probar</Button>
					<Button variant="ghost">Pausar</Button>
					<Button className="ml-auto" variant="link">
						Eliminar
					</Button>
				</SheetFooter>
			</SheetContent>
		</Sheet>
	);
}

Drawer inferior

side="bottom" para acciones rápidas en pantallas chicas, como compartir un pulso.

Código
bottom.tsx
import { Button } from "@moodinary/ui/components/button";
import { CopyIcon } from "@moodinary/ui/components/icons";
import {
	Sheet,
	SheetClose,
	SheetContent,
	SheetDescription,
	SheetHeader,
	SheetTitle,
	SheetTrigger,
} from "@moodinary/ui/components/sheet";

export default function SheetBottom() {
	return (
		<Sheet>
			<SheetTrigger render={<Button variant="secondary" />}>
				Abrir drawer inferior
			</SheetTrigger>
			<SheetContent
				className="rounded-t-[14px]"
				showCloseButton={false}
				side="bottom"
			>
				<div
					aria-hidden
					className="mx-auto mt-2 h-1 w-9 rounded-full bg-line-2"
				/>
				<SheetHeader>
					<SheetTitle>Compartir pulso</SheetTitle>
					<SheetDescription>
						Mostrá el QR al grupo o copiá el link.
					</SheetDescription>
				</SheetHeader>
				<div className="flex gap-2 px-4 pb-6">
					<SheetClose render={<Button />}>
						<CopyIcon />
						Copiar link
					</SheetClose>
					<SheetClose render={<Button variant="secondary" />}>
						Cerrar
					</SheetClose>
				</div>
			</SheetContent>
		</Sheet>
	);
}

Props

SheetContent

PropTipoDefaultDescripción
side"top" | "right" | "bottom" | "left""right"Desde qué borde entra.
showCloseButtonbooleantrueMuestra la X arriba a la derecha.

Sheet

PropTipoDefaultDescripción
openboolean-Estado controlado.
onOpenChange(open: boolean) => void-Se llama al abrir o cerrar.

Cuándo sí y cuándo no

Hacé
  • Usalo para detalles que se consultan y se cierran.
  • Dejá las acciones abajo, siempre visibles.
  • Abrilo desde abajo en mobile.
Evitá
  • No lo uses para formularios largos; eso merece una página.
  • No apiles dos sheets.
  • No pongas datos de participantes individuales: los pulsos son anónimos.

Accesibilidad

  • Esc cierra y el foco queda atrapado adentro.
  • El foco vuelve al disparador al cerrar.
  • El título tiene que describir qué se abrió.