KDS
Overlays

Sheet

Painel lateral para fluxos longos — filtros, settings, edições multi-seção.

Overview

Sheet é um painel ancorado a uma das bordas da viewport — direita por padrão. Use para conteúdo que é longo demais para Dialog mas não merece página inteira: filtros, painéis de configuração, edições multi-seção, painéis de detalhe.

A diferença mental versus Dialog: Dialog é uma decisão; Sheet é uma sessão de trabalho que o usuário pode salvar e fechar quando quiser. Use a borda certa para o conteúdo:

BordaUso típico
rightFiltros, painéis de detalhe, edição contextual (default)
leftNavegação principal em mobile
bottomAções rápidas em mobile
topNotificações globais (raro)
Preview
Sheet com formulário de edição.

Anatomy

<Sheet>
  <SheetTrigger />
  <SheetContent side="right">
    <SheetHeader>
      <SheetTitle />
      <SheetDescription />
    </SheetHeader>
    {/* conteúdo do sheet */}
    <SheetFooter>
      <Button>Salvar</Button>
      <SheetClose>Cancelar</SheetClose>
    </SheetFooter>
  </SheetContent>
</Sheet>

Subcomponents

ComponenteDescrição
SheetRaiz.
SheetTriggerElemento que abre o sheet.
SheetContentContainer portalado e ancorado à borda. Aceita side.
SheetHeaderWrapper do título + descrição.
SheetTitleTítulo obrigatório.
SheetDescriptionDescrição opcional.
SheetFooterRodapé com ações.
SheetCloseWrapper que fecha o sheet ao clicar.

Usage

import {
  Sheet,
  SheetTrigger,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetDescription,
  SheetFooter,
  SheetClose
} from "@kalvner/kds/overlays/sheet";
import { Button } from "@kalvner/kds/forms/button";

export function FilterPanel() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="outline">Filtros</Button>
      </SheetTrigger>
      <SheetContent>
        <SheetHeader>
          <SheetTitle>Filtros</SheetTitle>
          <SheetDescription>
            Refine os resultados pelos critérios abaixo.
          </SheetDescription>
        </SheetHeader>
        {/* form */}
        <SheetFooter>
          <Button>Aplicar</Button>
          <SheetClose asChild>
            <Button variant="outline">Limpar</Button>
          </SheetClose>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}

Props

SheetContent

PropTipoDefaultDescrição
side'top' | 'right' | 'bottom' | 'left''right'Borda de ancoragem.
showCloseButtonbooleantrueMostra o X no canto.

Variants

Right (default)
Filtros, detalhes.
Left
Navegação mobile.
Top
Notificação global.
Bottom
Ações rápidas mobile.

When to use

  • Filtros que vão evoluir (10+ campos, condicionais).
  • Edição de um item com múltiplas seções.
  • Painel de detalhe que coexiste com a lista (master-detail).
  • Configurações secundárias (preferências de view, atalhos).

When not to use

  • Para uma única decisão curta — use Dialog.
  • Para ações inline contextuais — use Popover.
  • Para confirmação destrutiva crítica — use AlertDialog.
  • Para mobile com gesto natural de arrastar — use Drawer.

Best practices

  • Header sticky em fluxos longos. Quando o conteúdo rola, mantenha Title e Description visíveis para que o usuário não perca o contexto.
  • Footer sticky para ações primárias. Salvar / Aplicar / Cancelar devem ficar sempre visíveis. Use mt-auto no SheetFooter.
  • Largura responsiva. Default w-3/4 em mobile e sm:max-w-sm em desktop. Ajuste para conteúdo mais largo (sm:max-w-lg) se precisar.
  • Não substitua navegação. Sheet é overlay — perder estado é esperado. Para fluxos que precisam ser bookmarkable, use rota.

Accessibility

ConcernComportamento
RolesRadix Dialog aplica role="dialog" + aria-modal="true".
FocoFocus trap ativo. Escape fecha. Foco volta ao trigger.
KeyboardTab/Shift+Tab cicla. Esc fecha.
Screen readerSheetTitle é o nome; SheetDescription é a descrição.
Touch targetBotão de close (X) tem 24px de área visível mas hit-area maior por padding.
Reduced motionSlide animation respeita prefers-reduced-motion.
  • Dialog — para decisões curtas e centradas.
  • Drawer — bottom sheet mobile-first.
  • Popover — para conteúdo inline contextual.

On this page