Avançados: essenciais
Toggles, label, regiões expansíveis, menus disparados por interação e a paleta de comandos. A fatia que quase toda tela usa em algum momento.
Toggle
Seção form-primitives da gallery — rode localmente para interagir.
Botão de dois estados — como um checkbox estilizado de botão. Controlado (pressed + onPressedChange) ou não-controlado (defaultPressed).
import { Toggle } from "tempest-react-sdk";
<Toggle
defaultPressed
variant="outline"
size="md"
onPressedChange={(pressed) => console.log(pressed)}
>
Negrito
</Toggle>;
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
pressed |
boolean |
— | Estado controlado. Quando definido, vira controlado |
defaultPressed |
boolean |
false |
Estado inicial no modo não-controlado |
onPressedChange |
(pressed: boolean) => void |
— | Disparado com o próximo estado ao ativar |
size |
"sm" \| "md" \| "lg" |
"md" |
Tamanho visual |
variant |
"default" \| "outline" |
"default" |
Estilo visual |
Demais props de <button> são repassadas.
A11y
Renderiza um <button type="button"> nativo expondo o estado via aria-pressed e data-state="on"|"off".
ToggleGroup (+ ToggleGroupItem)
Seção feedback-extra da gallery — rode localmente para interagir.
Conjunto de toggles que compartilham estado de seleção via contexto. Modo single (valor string) ou multiple (valor string[]).
import { ToggleGroup, ToggleGroupItem } from "tempest-react-sdk";
<ToggleGroup type="single" defaultValue="left" onValueChange={(value) => console.log(value)}>
<ToggleGroupItem value="left">Esquerda</ToggleGroupItem>
<ToggleGroupItem value="center">Centro</ToggleGroupItem>
<ToggleGroupItem value="right">Direita</ToggleGroupItem>
</ToggleGroup>;
ToggleGroup:
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
type |
"single" \| "multiple" |
"single" |
single mantém um valor; multiple mantém um conjunto |
value |
string \| string[] |
— | Valor controlado (string para single, string[] multi) |
defaultValue |
string \| string[] |
— | Valor inicial não-controlado |
onValueChange |
(value: string \| string[]) => void |
— | Disparado com o próximo valor |
children |
ReactNode |
— | Itens ToggleGroupItem |
ToggleGroupItem:
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
value |
string |
— | Valor estável que identifica o item |
disabled |
boolean |
— | Desabilita o item |
children |
ReactNode |
— | Conteúdo do item |
Single mode
Em single, onValueChange recebe "" (string vazia) quando nada está selecionado.
Label
Seção inputs-extra da gallery — rode localmente para interagir.
Um <label> de formulário. Associe a um controle via htmlFor. Com required, anexa um asterisco decorativo (aria-hidden).
import { Label } from "tempest-react-sdk";
<Label htmlFor="email" required>
E-mail
</Label>;
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
required |
boolean |
false |
Anexa um asterisco em cor de perigo marcando campo obrigatório |
Demais props de <label> (incl. htmlFor) são repassadas.
Collapsible
Seção disclosure da gallery — rode localmente para interagir.
Uma única região expandir/recolher — alternativa mais leve ao Accordion para um bloco. Controlado (open + onOpenChange) ou não-controlado (defaultOpen).
import { Collapsible } from "tempest-react-sdk";
<Collapsible trigger="Ver detalhes" defaultOpen={false}>
<p>Conteúdo revelado ao expandir.</p>
</Collapsible>;
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
open |
boolean |
— | Estado controlado. Quando definido, vira controlado |
defaultOpen |
boolean |
false |
Estado inicial não-controlado |
onOpenChange |
(open: boolean) => void |
— | Disparado com o próximo estado ao ativar o gatilho |
trigger |
ReactNode |
— | Conteúdo renderizado dentro do botão gatilho |
children |
ReactNode |
— | Conteúdo recolhível, oculto enquanto fechado |
A11y
O gatilho é um <button aria-expanded aria-controls> ligado a uma role="region" de mesmo id; a região fica hidden enquanto fechada.
ContextMenu
Seção overlays da gallery — rode localmente para interagir.
Menu de ações. Abre na posição do ponteiro por clique direito, por toque longo e — quando você pede — por clique esquerdo; renderizado por um Portal, preso dentro da viewport. Fecha no clique fora, Escape, rolagem, resize ou seleção.
import { ContextMenu } from "tempest-react-sdk";
<ContextMenu
items={[
{ label: "Editar", onSelect: () => edit() },
{ label: "Duplicar", onSelect: () => duplicate() },
{ separator: true },
{ label: "Excluir", danger: true, onSelect: () => remove() },
]}
>
<div>Clique direito aqui</div>
</ContextMenu>;
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
items |
ContextMenuItem[] |
— | Entradas do menu — itens selecionáveis e separadores |
children |
ReactNode |
— | Área de gatilho; o gesto em qualquer parte dela abre |
className |
string |
— | Classes extras repassadas ao elemento do menu |
trigger |
"contextmenu" \| "click" \| "both" |
"contextmenu" |
Qual gesto de mouse abre o menu |
longPressDelay |
number (ms) |
500 |
Duração do toque longo; 0 desliga |
viewportMargin |
number (px) |
8 |
Folga mantida entre o menu e a borda da tela |
ContextMenuItem = { label: ReactNode; onSelect?: () => void; disabled?: boolean; danger?: boolean } ou { separator: true }.
Toque não tem clique direito — e o browser não te dá um substituto
Medido no Chrome com emulação de toque (perfis Pixel 7 e iPhone 13), um toque
segurado por 900 ms num elemento comum produz pointerdown, touchstart,
pointerup, touchend e click — e nenhum contextmenu. Um menu que só
escutasse contextmenu deixaria toda ação atrás dele inalcançável no celular,
sem erro nenhum: ele simplesmente nunca abre.
Por isso o toque longo é default, e independe de trigger (que só decide o
gesto de mouse). O timer é cancelado quando o dedo anda mais de 10 px — senão
toda rolagem que começa sobre o gatilho abriria um menu — e o click que o dedo
deixa para trás é engolido, para abrir o menu sobre um balão de conversa não
abrir também o balão.
O padrão ⋮
Um botão de três pontinhos deve responder ao clique esquerdo. Envolva-o com
trigger="click":
<ContextMenu trigger="click" items={items}>
<Button variant="ghost" aria-label="Mais ações">⋮</Button>
</ContextMenu>
"both" mantém os dois botões, para um alvo que aceita as duas formas.
Preso dentro da viewport
O menu é medido depois de montar e puxado para dentro da tela. Antes disso,
medido em 320 px de largura: um menu de 180 px aberto em x=235 ia até 415 —
95 px fora da tela, cortando a borda direita de todo rótulo.
Teclado
O menu recebe o foco ao abrir, então o leitor de tela anuncia o menu em vez de
ficar no gatilho. Setas ↑/↓ percorrem os itens selecionáveis e dão a volta,
Home/End vão para as pontas, Enter ativa e Escape fecha.
HoverCard
Pré-visualização de conteúdo exibida ao passar o mouse ou focar o gatilho. Abre após openDelay, fecha após closeDelay.
import { HoverCard } from "tempest-react-sdk";
<HoverCard trigger={<a href="/u/maria">@maria</a>} placement="bottom">
<div>
<strong>Maria Silva</strong>
<p>Engenheira de software · 2.3k seguidores</p>
</div>
</HoverCard>;
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
trigger |
ReactNode |
— | Elemento que o usuário foca/aponta para revelar |
children |
ReactNode |
— | Conteúdo do card |
openDelay |
number (ms) |
300 |
Atraso antes de abrir em mouseenter/focus |
closeDelay |
number (ms) |
150 |
Atraso antes de fechar em mouseleave/blur |
placement |
"top" \| "bottom" \| "left" \| "right" |
"bottom" |
Ancoragem do card relativa ao gatilho |
portal |
boolean |
true |
Card em document.body: escapa de overflow e vira na borda da tela; um link no card é o próximo Tab depois do gatilho |
A11y
O card é uma role="dialog" rotulada; o gatilho permanece focável por teclado.
Command (paleta ⌘K)
Paleta de comandos estilo ⌘K: diálogo em overlay com input que filtra itens por substring (label + keywords), agrupa resultados e suporta navegação por teclado (↑/↓, Enter, Escape). Prende o foco enquanto aberto.
import { Command } from "tempest-react-sdk";
import { useState } from "react";
const [open, setOpen] = useState(false);
<Command
open={open}
onOpenChange={setOpen}
placeholder="Digite um comando…"
items={[
{ id: "new", label: "Novo documento", group: "Arquivo", onSelect: () => create() },
{
id: "open",
label: "Abrir…",
group: "Arquivo",
keywords: ["recente"],
onSelect: () => openFile(),
},
{ id: "theme", label: "Alternar tema", group: "Preferências", onSelect: () => toggleTheme() },
]}
/>;
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
open |
boolean |
— | Se a paleta está visível |
onOpenChange |
(open: boolean) => void |
— | Próximo estado (Escape, seleção, clique no backdrop) |
items |
CommandItem[] |
— | Candidatos a filtrar e exibir |
placeholder |
string |
"Type a command…" |
Placeholder do input de busca |
emptyMessage |
ReactNode |
"No results" |
Exibido quando nada combina com a busca |
className |
string |
— | Repassado ao elemento de diálogo |
CommandItem = { id: string; label: string; group?: string; keywords?: string[]; onSelect: () => void; icon?: ReactNode }.
Gatilho global
Combine com useKeyboardShortcut("mod+k", () => setOpen(true)) para abrir via ⌘K / Ctrl+K.
Recap
- Essenciais:
Toggle/ToggleGrouppara estados pressionáveis,Labelpara formulários,Collapsiblepara um bloco expansível,ContextMenu/HoverCardpara overlays disparados por interação eCommandpara a paleta ⌘K. - Todos seguem os mesmos padrões controlado/não-controlado, expõem A11y por teclado e importam de
tempest-react-sdk.




