Drawer
Um painel que desliza a partir de qualquer borda e acompanha o seu dedo, com pontos de ancoragem, uma alça funcional e drawers aninhados que se empilham.
pnpm dlx shadcn@latest add https://hextaui.com/r/drawer.jsonAdiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.
Adicione os tokens de tema ao seu CSS global, se ainda não o fez.
Instale as dependências.
pnpm add @base-ui/react @tabler/icons-react cnCopie e cole o código a seguir no seu projeto.
components/ui/drawer.tsx components/ui/sheet.tsx components/ui/button.tsx Atualize os caminhos de importação para corresponder à configuração do seu projeto.
Direções
Defina swipeDirection em <Drawer /> para escolher a borda. O drawer abre a partir dessa borda e desliza de volta em direção a ela. Drawers superior e inferior exibem uma alça por padrão.
Snap points
Passe snapPoints para fazer um drawer inferior parar em alturas predefinidas. Números de 0 a 1 são frações do viewport, números maiores são pixels e strings aceitam px ou rem. A parte visível sempre se ajusta ao conteúdo, então nada fica escondido abaixo da tela.
Conteúdo rolável
<DrawerBody /> rola por conta própria, então o header e o footer permanecem no lugar. O deslize só começa quando o body volta ao topo.
Formulários e o teclado
Envolva <DrawerContent /> em <DrawerVirtualKeyboardProvider /> quando um drawer inferior contiver campos de texto. Em celulares, o campo em foco rola para a vista acima do teclado virtual em vez de ficar escondido atrás dele. Mantenha os campos em <DrawerBody /> para que o header e o footer fiquem no lugar.
Aninhado
Um drawer aberto a partir de um drawer na mesma borda fica empilhado por cima. Os de trás encolhem, aparecem acima dele e acompanham seu dedo quando você desliza o de cima para fora.
Confirmar a partir de um drawer
Diálogos, alert dialogs, sheets e drawers em outra borda ficam em camadas por cima em vez de empilhados. O drawer recua e um backdrop mais claro o cobre.
Responsivo
Altere swipeDirection com uma media query para mostrar um painel lateral no desktop e um bottom sheet em celulares.
Não modal
Com modal={false} não há backdrop, a página continua rolando e o foco pode sair do drawer.
Controlado
Passe open e onOpenChange para abri-lo de qualquer lugar, sem gatilho.
Gatilhos desanexados
Compartilhe um drawer entre vários gatilhos com createDrawerHandle. Cada gatilho passa um payload que o drawer renderiza por meio de uma função como filho.
Da direita para a esquerda
Passe dir="rtl" a <DrawerContent /> para espelhar seu conteúdo. swipeDirection nomeia uma borda física, então "left" permanece à esquerda e a alça permanece na borda interna.
| Tecla | Ação |
|---|---|
| EnterSpace | No gatilho, abre o drawer e move o foco para dentro dele. |
| TabShift + Tab | Alterna entre elementos focáveis. O foco permanece dentro de um drawer modal. |
| Esc | Fecha o drawer mais ao topo e devolve o foco ao seu gatilho. |
- O drawer é um diálogo.
<DrawerTitle />o rotula e<DrawerDescription />o descreve, então inclua sempre um título. - Deslizar nunca é a única saída: Escape, o backdrop e um botão
<DrawerClose />também o fecham. - A alça é decorativa e fica oculta para tecnologias assistivas. Com o mouse, o texto dentro do drawer pode ser selecionado sem arrastá-lo.
- Com movimento reduzido ativado, o drawer aparece e some com fade em vez de deslizar. O arraste ainda acompanha o ponteiro.
Construído sobre o drawer do Base UI. Cada parte aceita as props da primitiva que envolve.
| Prop | Tipo | Padrão |
|---|---|---|
swipeDirectionA borda de onde ele abre e a direção que o dispensa. | "up" | "down" | "left" | "right" | "down" |
showSwipeHandleMostra a alça. O padrão é true para up e down, e false para left e right. | boolean | – |
snapPointsAlturas em que um drawer vertical pode parar. 0–1 é uma fração do viewport, >1 são pixels, strings aceitam px ou rem. | (number | string)[] | – |
snapPoint | number | string | null | – |
defaultSnapPoint | number | string | null | – |
onSnapPointChange | (snapPoint, details) => void | – |
defaultOpen | boolean | false |
open | boolean | – |
onOpenChange | (open: boolean, details) => void | – |
onOpenChangeCompleteChamado após o fim da animação de abertura ou fechamento. | (open: boolean) => void | – |
modalO backdrop só é renderizado quando true. | boolean | "trap-focus" | true |
disablePointerDismissalMantém aberto quando o backdrop é clicado. | boolean | false |
handle | DrawerHandle<Payload> | – |
children | ReactNode | ({ payload }) => ReactNode | – |
| Prop | Tipo | Padrão |
|---|---|---|
handle | DrawerHandle<Payload> | – |
payload | Payload | – |
render | ReactElement | (props, state) => ReactElement | <button> |
| Atributo | Descrição |
|---|---|
data-slot="drawer-trigger" | Selecione o gatilho no CSS. |
data-popup-open | Presente enquanto o seu drawer está aberto. |
Renderiza o portal, o backdrop, o viewport e o popup, além da alça. Drawers verticais se ajustam ao conteúdo até a altura do viewport menos 4rem. Drawers laterais têm 75% de largura, até 24rem a partir do breakpoint sm. Substitua com h-* ou w-*, ou limite a um eixo com data-[swipe-axis=y]:.
| Prop | Tipo | Padrão |
|---|---|---|
initialFocus | boolean | RefObject | (type) => HTMLElement | boolean | – |
finalFocus | boolean | RefObject | (type) => HTMLElement | boolean | – |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descrição |
|---|---|
data-slot="drawer-popup" | O painel do drawer. |
data-slot="drawer-content" | O wrapper interno em volta dos seus children. Ele rola quando nada mais rola. |
data-swipe-direction | up, right, down ou left. |
data-swipe-axis | x ou y. |
data-open | Presente enquanto o drawer está aberto. |
data-starting-style | Presente enquanto a animação de entrada ocorre. |
data-ending-style | Presente enquanto a animação de saída ocorre. |
data-swiping | Presente enquanto está sendo arrastado. |
data-snap-points | Presente quando o drawer tem snap points. |
data-expanded | Presente no snap point de altura total. |
data-nested-drawer-open | Presente enquanto outro drawer está aberto por cima. |
data-stack | Presente enquanto um drawer na mesma borda está empilhado por cima. |
--drawer-inset | Faz o drawer flutuar afastado das bordas do viewport. O padrão é 0px. |
--drawer-bleed-background | Preenche a área revelada ao arrastar além da borda. O padrão é a cor do popover. |
--drawer-swipe-movement-x | Distância de arraste horizontal. Também existe uma variável -y. |
--drawer-snap-point-offset | A que distância abaixo do topo está o snap point atual. |
--nested-drawers | Quantos drawers estão abertos por cima. |
Renderizado por <DrawerContent /> quando modal é true. Ele esmaece conforme você desliza e permanece pelo menos metade visível quando há snap points. Um drawer em camada sobre um sheet ou um drawer em outra borda recebe um backdrop mais claro.
| Atributo | Descrição |
|---|---|
data-slot="drawer-overlay" | O pano de fundo. |
data-nested | Presente em backdrops mais claros de drawers em camadas. |
--drawer-overlay-min-opacity | A menor opacidade a que ele esmaece ao deslizar. 0, ou 0.5 com snap points. |
Renderizado por <DrawerContent /> na borda interna quando showSwipeHandle está ativado. O drawer inteiro pode ser arrastado, então a alça é só uma pista visual.
| Atributo | Descrição |
|---|---|
data-slot="drawer-swipe-handle" | A alça. |
Elementos <div> simples que organizam o drawer. O header centraliza seu texto em drawers verticais em telas pequenas, o body rola e ocupa o espaço restante, e o footer empilha suas ações.
| Atributo | Descrição |
|---|---|
data-slot="drawer-header" | Título e descrição. |
data-slot="drawer-body" | Conteúdo rolável. |
data-slot="drawer-footer" | Ações. |
| Prop | Tipo | Padrão |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <h2> |
| Atributo | Descrição |
|---|---|
data-slot="drawer-title" | Rotula o drawer. |
| Prop | Tipo | Padrão |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <p> |
| Atributo | Descrição |
|---|---|
data-slot="drawer-description" | Descreve o drawer. |
Não renderiza nenhum elemento. Coloque-o dentro de <Drawer />, em volta de <DrawerContent />. Enquanto o teclado virtual está aberto, ele adiciona espaço abaixo do contêiner de rolagem do drawer, rola o campo em foco para a vista e faz toques em campos abrirem o teclado no iOS. Drawers sem ele não são afetados.
| Prop | Tipo | Padrão |
|---|---|---|
children | ReactNode | – |
| Atributo | Descrição |
|---|---|
--drawer-keyboard-inset | Definido no viewport enquanto o teclado está aberto: quanto dele se sobrepõe à página. Use com um fallback de 0px. |
| Prop | Tipo | Padrão |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <button> |
| Atributo | Descrição |
|---|---|
data-slot="drawer-close" | Fecha o drawer quando pressionado. |
createDrawerHandle<Payload>() retorna um handle que conecta um <Drawer /> a gatilhos renderizados em outro lugar. Crie-o uma vez, fora do seu componente.
- SheetUm painel que desliza a partir de qualquer borda, com deslize para dispensar, bloqueio de rolagem e aninhamento empilhado.
- Alert dialogUm diálogo de confirmação para ações destrutivas ou importantes que aguarda trabalho assíncrono e vira um bottom sheet no celular.
- CommandUma lista pesquisável de ações, inline ou como paleta ⌘K, com páginas, atalhos e correspondências destacadas.
- Context menuUm menu de ações ao clicar com o botão direito ou pressionar e segurar, com submenus, itens de checkbox e de rádio e feedback de pressão no toque.
- DialogUma janela sobre a página para formulários e tarefas focadas, com cabeçalho e rodapé fixos, aninhamento e um bottom sheet com deslize no celular.
- Dropdown menuUm menu de ações e opções atrás de um botão, com grupos, submenus, itens de checkbox e de rádio e atalhos.
Usado em blocos
Blocos que se baseiam em Drawer.