Configurações
Configurações para um produto de IA, organizadas como no Cursor e no Claude. Uma barra lateral preenchida com busca, grupos e links externos, cards de linhas com seletores discretos e opções aninhadas, uma ilha de salvar escura que só sobe quando algo muda, ⌘S para salvar, erros de campo vindos das suas verificações ou do seu servidor e estados de carregamento com o formato do conteúdo.
Cursor, Claude e Codex adotaram a mesma página de configurações: uma barra lateral preenchida com busca e um punhado de seções agrupadas e, à direita, cards de linhas com rótulo e descrição à esquerda e um controle discreto à direita. O Settings é essa página. Ele guarda suas seções e cuida das partes que toda página de configurações erra: perder edições, salvar duas vezes e a passagem de uma barra lateral no desktop para uma lista no celular.
As linhas aceitam qualquer controle. SettingsSelect é o seletor de valor compacto que esses apps usam, um pequeno botão com contorno que abre um menu de opções, e SettingsNumber é um stepper que você pode segurar para repetir. Ambos são nomeados pela sua linha, então os leitores de tela anunciam "Fonte do chat, Serifada". SettingsLink é uma linha que abre outra coisa, com um chevron ou uma seta para links que saem do app. SettingsNested abre deslizando as opções dependentes sob um switch, como o acesso à rede sob Run code. A busca filtra a barra lateral por rótulo, descrição e palavras-chave, e Enter abre a primeira correspondência. SettingsChoice transforma uma escolha em cards com imagem, para que as pessoas escolham um tema ou uma densidade pela aparência.
Nada é salvo até você mandar. Assim que um valor difere do que está salvo, uma ilha escura sobe da parte de baixo com Discard e Save, e a entrada da seção na barra lateral ganha um ponto. Mude de volta e a barra some. Tente abrir outra seção, voltar no celular ou fechar a aba, e a troca é bloqueada: a barra sacode e diz para salvar ou descartar primeiro, e o navegador pergunta antes de a aba fechar. ⌘S ou Ctrl+S salva de qualquer lugar.
Salvar mostra seu progresso no botão, depois a ilha encolhe em um check de Saved e desliza para fora. Se as suas verificações falharem, os campos mostram seus erros, o foco vai para o primeiro e a barra diz quantos corrigir. Se o servidor disser não, retorne erros para os campos ou lance um erro, e o rascunho permanece exatamente como foi digitado. Continue digitando enquanto salva e a barra permanece para as edições mais novas.
No celular, a barra lateral vira uma lista agrupada com descrições e chevrons. Tocar em uma seção a desliza para dentro sobre a lista, com um botão de voltar, e o foco vai para o seu título. Enquanto os dados de uma seção carregam, ela mostra um skeleton com formato de linhas de switches, ou o seu próprio pela prop skeleton, e um erro com Try again se o carregamento falhar.
Adicione o registro Pro ao components.json
components.json Adicione seu token
Crie um token na sua página de conta e coloque-o em
.env.localcomoHEXTAUI_PRO_TOKEN.Adicione o bloco
pnpm dlx shadcn@latest add @hextaui-pro/settings
Conecte uma seção à sua API
useSettingsForm mantém um rascunho dos valores que você passa. Retorne erros de campo de onSave para mostrá-los sob o campo, ou lance um erro para mostrar a mensagem na barra de salvar. De qualquer forma, o rascunho permanece.
Uma rota por seção
Controle a seção ativa com value e onValueChange para dar a cada seção sua própria URL. O shell ainda bloqueia a troca enquanto algo não está salvo, então onValueChange só dispara quando é seguro sair.
Carregamento e erros
Passe status enquanto os dados de uma seção carregam. O skeleton espera 150ms para que carregamentos rápidos nunca pisquem, e um estado de erro oferece Try again por meio de onRetry.
Anatomia
As partes que você compõe, de fora para dentro.
| Parte | Descrição |
|---|---|
SettingsShell | A página: a navegação das seções, a coluna de conteúdo, a barra de salvar e a proteção contra sair com alterações não salvas. |
SettingsSection | Uma seção. Só é renderizada enquanto está aberta, com seu título, ações opcionais e estados de carregamento ou erro. |
SettingsGroup | Um card com título de linhas, com um rodapé opcional para uma nota sobre o grupo. |
SettingsRow | Um rótulo, uma descrição e um controle, ligados entre si para leitores de tela, com o erro do campo abaixo. |
SettingsSelect | Um seletor discreto para um valor de uma lista curta. |
SettingsLink | Uma linha que abre uma página, um diálogo ou um link externo. |
SettingsNested | Opções dependentes que se abrem deslizando enquanto um switch pai está ligado. |
SettingsNumber | Um stepper numérico com − e + que se repetem enquanto pressionados, construído sobre o Number Field do Base UI. |
SettingsChoice | Cards com imagem para escolher uma opção, como um tema ou uma densidade, com semântica de radio. |
SettingsSkeleton | O placeholder de carregamento, configurável por linhas por grupo e formato do controle. |
useSettingsForm | O rascunho de uma seção. Acompanha o que mudou, valida, salva e conecta a seção à barra de salvar. |
useSettingsNavigate | Abre uma seção de dentro do conteúdo, protegida como a barra lateral. |
SettingsShell
Também aceita todas as props de div.
| Prop | Tipo | Padrão |
|---|---|---|
sections{ id, label, description?, icon?, group?, keywords?, href? }. Itens consecutivos com o mesmo group compartilham um título. keywords ajudam a busca a encontrar uma seção, e href faz do item um link externo. | SettingsSectionItem[] | – |
valueA seção aberta, quando você a controla. | string | – |
defaultValueA seção aberta inicialmente. | string | first section |
onValueChangeChamado quando alguém abre outra seção. Nunca é chamado enquanto algo não está salvo ou está sendo salvo. | (value: string) => void | – |
titleO título da página acima da navegação e o rótulo do botão de voltar no celular. | ReactNode | "Settings" |
descriptionUma linha sob o título. | ReactNode | – |
navHeaderConteúdo no topo da barra lateral, como um link Back para o app. | ReactNode | – |
searchableAdiciona um campo de busca acima das seções. | boolean | false |
navFooterConteúdo fixado na parte de baixo da barra lateral, como o usuário conectado. | ReactNode | – |
groupLabelsMostra o nome de cada grupo acima dele. Desligue para separar os grupos apenas por espaço; os nomes ainda rotulam os grupos para leitores de tela. | boolean | true |
SettingsSection
Também aceita todas as props de section.
| Prop | Tipo | Padrão |
|---|---|---|
idCorresponde a um id em sections. | string | – |
titleO título. | ReactNode | the section's label |
descriptionA linha sob o título. | ReactNode | the section's description |
actionsBotões ao lado do título. | ReactNode | – |
statusMostra um skeleton ou um erro no lugar dos children. | "ready" | "loading" | "error" | "ready" |
skeletonO que mostrar enquanto status é loading. | ReactNode | <SettingsSkeleton /> |
errorA mensagem do estado de erro. | ReactNode | – |
onRetryAdiciona Try again ao estado de erro. | () => void | – |
| Prop | Tipo | Padrão |
|---|---|---|
titleTítulo acima do card. | ReactNode | – |
descriptionUma linha discreta sob o título, sobre o assunto do grupo. | ReactNode | – |
footerUma faixa discreta na parte inferior do card, para notas como o que uma mudança afeta. | ReactNode | – |
| Prop | Tipo | Padrão |
|---|---|---|
labelRotula o controle dentro da linha. | ReactNode | – |
descriptionTexto de ajuda, lido junto com o controle. | ReactNode | – |
errorMarca o controle como inválido e mostra a mensagem sob a linha. | string | – |
layoutauto coloca o controle ao lado do rótulo quando o card é largo e abaixo dele quando é estreito. inline o mantém ao lado do rótulo, para switches. stacked sempre o coloca embaixo, para áreas de texto. | "auto" | "inline" | "stacked" | "auto" |
disabledDesabilita o campo da linha. | boolean | false |
SettingsSelect
Também aceita todas as props do Button.
| Prop | Tipo | Padrão |
|---|---|---|
valueO valor escolhido. | string | – |
onValueChangeChamado com o novo valor. | (value: string) => void | – |
optionsAs opções, em ordem. | { value, label }[] | – |
SettingsChoice
Um radio group, então as setas movem entre os cards. Também aceita todas as props do RadioGroup do Base UI.
| Prop | Tipo | Padrão |
|---|---|---|
valueA opção escolhida. | string | – |
onValueChangeChamado com a nova opção. | (value: string) => void | – |
optionsA imagem de cada card e o nome abaixo dela. | { value, label, preview }[] | – |
columnsCards por linha. 4 cai para 2 quando a linha é estreita. | 2 | 3 | 4 | 3 |
ratioPrévias 16:10, ou 2:1 para as mais baixas. | "card" | "wide" | "card" |
SettingsNumber
Também aceita todas as props do NumberField.Root do Base UI, como format e smallStep.
| Prop | Tipo | Padrão |
|---|---|---|
valueO número atual. | number | null | – |
onValueChangeChamado conforme o número muda. | (value: number | null) => void | – |
minValor mínimo. O botão − é desabilitado ali. | number | – |
maxValor máximo. O botão + é desabilitado ali. | number | – |
stepO quanto cada pressionamento ou tecla de seta altera o valor. | number | 1 |
SettingsLink
Também aceita todas as props de anchor. Renderiza um botão quando não há href.
| Prop | Tipo | Padrão |
|---|---|---|
labelO título da linha. | ReactNode | – |
descriptionUma linha sob o título. | ReactNode | – |
externalAbre o href em uma nova aba e mostra uma seta em vez de um chevron. | boolean | false |
| Prop | Tipo | Padrão |
|---|---|---|
openMostra as opções. Geralmente o valor do switch pai. | boolean | – |
| Prop | Tipo | Padrão |
|---|---|---|
groupsQuantas linhas cada grupo de placeholder tem. | number[] | [3, 2] |
controlA forma à direita de cada linha. | "switch" | "select" | "input" | "switch" |
useSettingsForm
Retorna { values, setValue, errors, dirty, status, save, discard }.
| Prop | Tipo | Padrão |
|---|---|---|
valuesO que está salvo agora. Quando muda e não há edições, o rascunho o acompanha. | Values | – |
onSaveSalva o rascunho. Retorne { field: message } para mostrar erros de campo, ou lance um erro para mostrar a mensagem na barra de salvar. | (values) => void | errors | Promise<void | errors> | – |
validateExecuta antes de onSave. Qualquer erro interrompe o salvamento e foca o primeiro campo inválido. | (values) => errors | undefined | – |
useSettingsNavigate
Retorna uma função que abre uma seção de qualquer lugar dentro do shell, como o botão Open de um banner. Ela respeita as alterações não salvas da mesma forma que a barra lateral.
| Prop | Tipo | Padrão |
|---|---|---|
navigateAbre a seção, ou sacode a barra de salvar se algo não está salvo. | (id: string) => void | – |
| Tecla | Ação |
|---|---|
| Tab | Percorre a navegação, depois a seção e depois a barra de salvar quando ela está aberta. |
| Enter | Abre a seção em foco. |
| ↑↓ | Em um stepper, altera o número em um passo. Shift move de dez em dez. |
| Enter | No campo de busca, abre a primeira seção correspondente. Escape limpa a busca. |
| ⌘S | Salva enquanto algo não está salvo. Ctrl+S no Windows e no Linux. |
- A navegação é um landmark, e a seção aberta é marcada como a página atual.
- Cada seção é uma região nomeada pelo seu título. No celular, o foco vai para o título quando uma seção abre e volta para a sua linha quando você retorna.
- As linhas usam o Field, então rótulos, descrições e erros ficam associados ao controle.
- A navegação bloqueada é anunciada de forma polite, e um salvamento com falha é anunciado como alerta.
- A barra de salvar e qualquer painel oculto são inert, então ficam fora da ordem de Tab e ocultos dos leitores de tela.
- Com movimento reduzido, os painéis esmaecem em vez de deslizar e o sacudir da barra de salvar vira um anel.
Construído com
Os componentes gratuitos do HextaUI de que Settings é feito. Cada um é instalado separadamente.
Código
6 arquivos, adicionados a components/blocks/settings.