Input Group

Formularioserver safe

Campo de texto composto com addon, botão ou texto acoplado, para variantes do campo combinado usado na boleta de operação.

Carregando

Instalação

Recebe correções por update de versão. O caminho recomendado.

npm i @trdr/ui

import { InputGroup } from "@trdr/ui/input-group"

Uso

import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText } from "@trdr/ui/input-group"

export function Exemplo() {
  return <InputGroup />
}

Variantes

GrupoValoresPadrão
size
defaultlg
default

Props

InputGroupPropsestende React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof inputGroupVariants>
InputGroupInputPropsestende Omit<InputProps, "size">
InputGroupAddonPropsestende React.HTMLAttributes<HTMLDivElement>
PropTipoDescrição
align?"start" | "end"Lado do container onde o addon fica: `start` antes do campo, `end` depois.
InputGroupButtonPropsestende React.ButtonHTMLAttributes<HTMLButtonElement>
InputGroupTextPropsestende React.HTMLAttributes<HTMLSpanElement>

Quando usar

Use o input-group quando um campo de texto precisa de algo grudado nele, com uma unica borda compartilhada: um prefixo de moeda, um sufixo de unidade, um icone de busca, ou um botao que abre um seletor (o caso da boleta de operacao, quantidade acoplada a unidade). Ele existe para os casos em que o iconLeft/onClear do Input sozinho nao bastam porque o elemento acoplado precisa de comportamento proprio (abrir algo, ser clicavel, ter o proprio rotulo).

Quando nao usar

Nao use input-group so para colocar um icone decorativo do lado do campo: se o icone e so enfeite sem interacao propria, o iconLeft do Input sozinho ja resolve com menos partes. Nao use para escolher entre opcoes fechadas sem campo de texto: isso e o select.

Anatomia

<InputGroup data-slot="input-group">                   raiz: borda unica, fundo, altura
  <InputGroupAddon data-slot="input-group-addon">       opcional, align="start" ou "end"
    <InputGroupText data-slot="input-group-text" />     texto/icone estatico
    <InputGroupButton data-slot="input-group-button" /> acao acoplada
  </InputGroupAddon>
  <InputGroupInput />                                   o campo, por baixo e um Input
</InputGroup>

InputGroupAddon so posiciona (align="start" antes do campo, align="end" depois, via order-first/order-last, entao a ordem no DOM nao precisa acompanhar a ordem visual). Quem tem padding proprio sao as pecas de dentro (InputGroupText, InputGroupButton): assim um botao pode ocupar a lateral inteira do grupo, rente a borda, do mesmo jeito que o chevron do combo input legado tocava a borda direita.

Variantes

  • size no InputGroup: default (24px) e lg (32px). O InputGroupInput nao tem size proprio: a altura vem sempre do grupo pai, porque um campo e o addon ao lado precisam ter a mesma altura, nao alturas independentes que o consumidor tem que sincronizar a mao.
  • align no InputGroupAddon: start ou end.

Migracao do componente legado

O ComboInput do Hub antigo (ComboInput.tsx + .trdr-combo-input) era fechado: um state unico (default | hover | selected-input | selected-chevron) controlava dois segmentos com borda propria cada (o valor e o chevron), incluindo o detalhe do chevron ficar com fundo surface-brand quando "selecionado". Isso funcionava bem para o caso especifico da boleta, mas nao generalizava: nao dava para trocar o chevron por um icone de busca, ou adicionar um prefixo de texto, sem reescrever o componente inteiro.

Aqui isso vira composicao sobre o Input que ja existe:

  • o antigo value/onChange (o campo, sempre texto fixo no legado) vira InputGroupInput, que por baixo e o proprio Input do TRDR UI com a borda e o fundo neutralizados via wrapperClassName (por isso o campo renderizado carrega tanto data-slot="input" quanto o contexto do grupo ao redor: input-group nao duplica o campo, reaproveita)
  • o antigo onChevronClick vira um InputGroupButton dentro de um InputGroupAddon align="end"
  • o destaque de fundo do chevron "selecionado" (state="selected-chevron") vira aria-expanded={true} no InputGroupButton: o mesmo atributo de acessibilidade que um botao controlando um menu ja precisa ter, sem inventar um data-state novo. O InputGroup detecta isso sozinho via has-[[data-slot=input-group-button][aria-expanded=true]] e tinge a borda inteira, nao so o segmento do botao

Essa e uma simplificacao deliberada do espacamento: o legado tinha os dois segmentos com bordas independentes que se fundiam visualmente; aqui e uma borda unica ao redor do grupo inteiro, e o espacamento interno e um pouco mais generoso por composicao (o Input de dentro mantem o proprio px-sm). Para o encaixe mais compacto do legado, ajuste via wrapperClassName no InputGroupInput.

Acessibilidade

  • O ref do InputGroupInput aponta para o <input> nativo, herdando o comportamento do Input.
  • Todo InputGroupInput sem rotulo visivel precisa de aria-label, e todo InputGroupButton sem texto visivel tambem (por exemplo um botao so com icone de chevron).
  • Estado desabilitado em qualquer peca interna (InputGroupInput ou InputGroupButton) tinge a borda do grupo inteiro via has-[:disabled], sem precisar de uma prop disabled redundante no InputGroup pai.
  • Quando o InputGroupButton controla um overlay (um menu de unidade, por exemplo), use aria-expanded para refletir o estado real: alem de ser exigido para leitor de tela, e o gancho que acende o destaque visual do grupo inteiro.

Slots e tokens

Todo elemento renderizado carrega um data-slot para estilizar partes internas sem depender de classe da biblioteca. Os tokens listados são extraídos do código fonte.

[data-slot="input"][data-slot="input-group"][data-slot="input-group-addon"][data-slot="input-group-button"][data-slot="input-group-text"]
15 tokens usados
bg-surface-brandbg-surface-primarybg-surface-secondarybg-transparentborder-border-strongborder-ringoutline-nonering-offset-2ring-offset-backgroundring-ringtext-b3text-content-brandtext-content-disabledtext-content-primarytext-content-tertiary