Makuco UI
ComponentesData Entry & Selection

Input Tag

Campo de texto que acumula termos livres como chips, com limite visível, ingestão de texto colado e associação a formulários.

O mk-input-tag é o mk-input com uma faixa de mk-chip dentro do campo. O usuário digita um termo, confirma com a tecla definida por triggerOn, e o termo vira um chip. Use quando a lista de valores é aberta — palavras-chave de um artigo, e-mails de convidados, filtros de uma busca, domínios permitidos. Quando os valores vêm de um conjunto fechado, o componente certo é o mk-select com kind="multiple".

Padrão

O componente é totalmente controlado: ele nunca escreve em tags. Sem um handler devolvendo o array atualizado, pressionar Enter não faz nada aparecer. Este é o uso mínimo real — comece por ele.

import { useState } from 'react';
import { MkInputTag } from '@db1/makuco-ui-react';

const [tags, setTags] = useState<string[]>([]);

<MkInputTag
  label="Palavras-chave"
  placeholder="Digite e pressione Enter"
  tags={tags}
  onMkTagAdd={(e) => setTags((prev) => [...prev, ...e.detail])}
  onMkTagRemove={(e) => setTags((prev) => prev.filter((t) => t !== e.detail))}
/>
<mk-input-tag
  label="Palavras-chave"
  placeholder="Digite e pressione Enter"
  [tags]="tags"
  (mkTagAdd)="onAdd($event)"
  (mkTagRemove)="onRemove($event)"
></mk-input-tag>
tags: string[] = [];

onAdd(e: CustomEvent<string[]>) { this.tags = [...this.tags, ...e.detail]; }
onRemove(e: CustomEvent<string>) { this.tags = this.tags.filter((t) => t !== e.detail); }

mkTagAdd carrega string[], não string. Escrever [...prev, e.detail] sem o spread interno injeta um array dentro do array de strings. E reatribua sempre o array: tags.push(x) não muda a referência e não dispara re-render.

Tecla de confirmação

triggerOn define o que confirma o rascunho: enter (padrão), space ou both.

<MkInputTag label="Etiquetas" triggerOn="space" tags={tags} onMkTagAdd={handleAdd} />
<mk-input-tag label="Etiquetas" trigger-on="space" [tags]="tags" (mkTagAdd)="onAdd($event)"></mk-input-tag>

Com space ou both, tags de múltiplas palavras deixam de ser possíveis — o espaço confirma o termo, então "São Paulo" nunca vira uma tag única. Use enter quando os termos puderem ter espaço.

Duplicatas

Por padrão um termo já presente em tags é descartado sem emitir evento, e o rascunho é limpo. Com allowDuplicates o componente não julga o conteúdo.

<MkInputTag label="Ocorrências" allowDuplicates tags={tags} onMkTagAdd={handleAdd} />
<mk-input-tag label="Ocorrências" allow-duplicates [tags]="tags" (mkTagAdd)="onAdd($event)"></mk-input-tag>

Limite visível e chip +N

O campo tem uma linha só. visibleTags (padrão 3) corta a renderização e resume o excedente em um chip +N, renderizado na própria faixa de chips — logo depois do último chip visível e antes do campo de digitação, para ser lido como a continuação da lista.

<MkInputTag
  label="Convidados"
  tags={tags}
  visibleTags={3}
  onMkTagAdd={handleAdd}
  onMkTagRemove={handleRemove}
  onMkOverflowClick={(e) => openDrawer(e.detail)}
  onMkTagsOverflow={(e) => setHiddenCount(e.detail.overflow)}
/>
<mk-input-tag
  label="Convidados"
  [tags]="tags"
  [visibleTags]="3"
  (mkTagAdd)="onAdd($event)"
  (mkTagRemove)="onRemove($event)"
  (mkOverflowClick)="openDrawer($event.detail)"
  (mkTagsOverflow)="hiddenCount = $event.detail.overflow"
></mk-input-tag>

Três pontos que costumam surpreender:

  • visibleTags é corte visual, não regra de negócio.

    Nunca impede a inclusão de uma nova tag e nunca recorta o valor enviado ao formulário. Para barrar a 11ª tag, simplesmente não a acrescente ao array ao receber mkTagAdd.

  • 0 ou negativo desliga o corte

    e renderiza todas as tags, com scroll horizontal na faixa.

  • Ignorar mkOverflowClick deixa as tags escondidas inacessíveis

    — nem por mouse, nem por teclado, nem por leitor de tela. O padrão previsto é abrir um drawer de gerenciamento (mk-drawer + mk-input-tag), que é composição da aplicação.

Colar e validar termos

Colar "ana@x.com, bruno@x.com" produz um mkTagAdd com os dois termos. separator quebra o texto em termos e pattern decide o que é aceitável. Os quatro caminhos de inclusão — tecla de trigger, caractere separador, paste e blur — passam pelo mesmo pipeline.

<MkInputTag
  label="Convidados"
  tags={tags}
  pattern="^\S+@\S+\.\S+$"
  separator={/[,;\n]+/}
  onMkTagAdd={handleAdd}
/>
<mk-input-tag
  label="Convidados"
  pattern="^\S+@\S+\.\S+$"
  separator="[,;\n]+"
  [tags]="tags"
  (mkTagAdd)="onAdd($event)"
></mk-input-tag>

Termos rejeitados pelo pattern voltam para o rascunho, rejuntados: colar "ok@x.com, invalido, outro@x.com" resulta em dois chips e o texto invalido no campo, pronto para correção. O componente não pinta borda de erro por conta disso — mostrar o porquê é decisão do consumidor, via errorMessage.

pattern é ancorado implicitamente (^(?:…)$), como o pattern nativo do <input>: "abc" com pattern="b" é rejeitado. Ambas as props aceitam string — compilada com new RegExp, e por isso utilizável como atributo HTML — ou RegExp, quando é preciso controlar flags.

Texto de suporte e erro

errorMessage coloca o campo em estado inválido: borda e rótulo em erro e aria-invalid="true" no input. Os chips continuam interativos.

<MkInputTag label="Palavras-chave" required errorMessage="Informe ao menos uma palavra-chave" tags={tags} />
<mk-input-tag
  label="Palavras-chave"
  required
  error-message="Informe ao menos uma palavra-chave"
  [tags]="tags"
></mk-input-tag>

Estados

Em disabled e readonly os chips perdem o ⊗ e nenhuma inclusão ou remoção é possível — nem por tecla, nem por paste, nem no blur. O chip +N continua visível e clicável: consultar não é editar.

<MkInputTag label="Somente leitura" readonly tags={tags} />
<MkInputTag label="Desabilitado" disabled tags={tags} />
<mk-input-tag label="Somente leitura" readonly [tags]="tags"></mk-input-tag>
<mk-input-tag label="Desabilitado" disabled [tags]="tags"></mk-input-tag>

Ícone à direita e busca

trailingIcon exibe um ícone decorativo. Com trailingIconLabel ele vira interativo (role="button", focável) e emite mkTrailingIconClick.

<MkInputTag
  label="Filtros aplicados"
  type="search"
  trailingIcon="search"
  trailingIconLabel="Buscar"
  tags={tags}
  onMkTrailingIconClick={handleSearch}
/>
<mk-input-tag
  label="Filtros aplicados"
  type="search"
  trailing-icon="search"
  trailing-icon-label="Buscar"
  [tags]="tags"
  (mkTrailingIconClick)="handleSearch()"
></mk-input-tag>

Formulários

O componente é form-associated. O valor enviado é JSON.stringify(tags) — a lista completa, nunca a recortada por visibleTags, e sempre JSON, inclusive "[]" quando vazio, para o backend ter um único caminho de parse. Imune a tags que contenham vírgula, aspas ou espaço.

required valida a quantidade de tags (valueMissing quando tags.length === 0), não o rascunho: um campo com texto digitado mas nenhuma tag confirmada continua inválido.

<form onSubmit={handleSubmit}>
  <MkInputTag label="Palavras-chave" name="keywords" required tags={tags} onMkTagAdd={handleAdd} />
</form>
import { MkInputTagModule } from '@db1/makuco-ui-angular';
<!-- o value accessor usa string[] como valor do controle -->
<mk-input-tag label="Palavras-chave" name="keywords" required [(ngModel)]="keywords"></mk-input-tag>

Autofill do navegador

Defina autocomplete com um token do HTML para habilitar o autofill do navegador no rascunho digitado — por exemplo, sugerir um e-mail salvo ao convidar destinatários.

<MkInputTag
  label="E-mail dos destinatários"
  autocomplete="email"
  pattern="^\S+@\S+\.\S+$"
  tags={tags}
  onMkTagAdd={handleAdd}
/>
<mk-input-tag
  label="E-mail dos destinatários"
  autocomplete="email"
  pattern="^\S+@\S+\.\S+$"
  [tags]="tags"
  (mkTagAdd)="onAdd($event)"
></mk-input-tag>

Props

PropTipoPadrãoDescrição
labelstringTexto do rótulo exibido acima do campo. Obrigatório.
tagsstring[][]Lista completa de tags. Somente leitura — o componente nunca escreve nela.
valuestring

Texto em rascunho: o que está digitado e ainda não virou tag. Não confundir com tags.

triggerOn"enter" | "space" | "both""enter"Tecla que confirma o rascunho como tag.
allowDuplicatesbooleanfalsePermite termos repetidos. A deduplicação também vale dentro de um lote colado.
visibleTagsnumber3Máximo de chips renderizados; o excedente vira +N. 0 ou negativo mostra tudo.
separatorstring | RegExp/(?:\r?\n|,|;|\t)+/Quebra o texto digitado ou colado em vários termos. Não inclui espaço.
patternstring | RegExp | nullnull

Cada termo precisa casar para virar tag. Ancorado implicitamente. Rejeitados voltam ao rascunho.

type"text" | "search""text"Tipo do input nativo.
placeholderstringPlaceholder exibido quando não há rascunho digitado.
supportTextstringTexto de suporte abaixo do campo quando não há erro.
helperTextstringTexto exibido no ícone de ajuda ao lado do rótulo. Quando omitido, o ícone não é exibido.
errorMessagestringMensagem de erro. Quando definida, o campo entra em estado inválido.
maxLengthnumberLimite de caracteres do rascunho. Não exibe contador e não se aplica a texto colado.
trailingIconIconNameÍcone Lucide exibido no lado direito do campo.
trailingIconLabelstringRótulo acessível do ícone trailing. Quando definido, o ícone vira interativo.
namestringAtributo name para envio em formulários.
requiredbooleanfalseMarca o campo como obrigatório. Valida a quantidade de tags, não o rascunho.
requiredMessagestring"This field is required"Mensagem de validação nativa quando required e sem nenhuma tag.
disabledbooleanfalseDesabilita o campo e remove o ⊗ dos chips.
readonlybooleanfalseCampo somente leitura; chips visíveis sem ⊗.
autocompletestringToken autocomplete do HTML repassado ao input nativo, para habilitar o autofill do navegador no rascunho.

Eventos

EventoPayloadDescrição
mkTagAddstring[]Termos confirmados, com trim(), filtrados e deduplicados. Sempre um array. Não dispara com lote vazio nem em disabled/readonly.
mkTagRemovestringTermo removido pelo ⊗ ou por Backspace com o rascunho vazio (remove a última tag, visível ou não).
mkTagsOverflow{ total, visible, overflow }Quando a quantidade escondida muda, incluindo a volta para 0.
mkOverflowClickstring[]As tags escondidas, ao ativar o +N. Dispara também com o campo disabled ou readonly.
mkInputstringO rascunho atual, sempre que ele muda.
mkChangestringO rascunho, quando mudou e o campo perde o foco. Carrega o texto, não as tags.
mkFocusvoidO campo recebe foco.
mkBlurvoidO campo perde o foco, depois do eventual mkTagAdd do rascunho pendente.
mkTrailingIconClickvoidÍcone trailing interativo ativado. Só quando trailingIconLabel está definido.

Acessibilidade

O campo é um <input type="text"> real associado ao <label> por htmlFor/id — sem roles inventados. Os chips usam botões nativos e o +N é um <button> de verdade.

  • aria-required, aria-invalid e aria-describedby são aplicados conforme required, errorMessage e supportText.
  • Uma região role="status" aria-live="polite" narra cada inclusão e remoção com o nome da tag e o total. Lotes colados geram um anúncio, não N. Tags que entram escondidas atrás do +N também são anunciadas.
  • Cada ⊗ tem nome acessível único (Remover {tag}). O +N tem o nome no <button> (Mais {n} tags não exibidas) e o chip interno é aria-hidden — lido literalmente, "+3" viraria "mais três", sem dizer de quê.
  • Clicar na área vazia do campo foca o input, e não o ⊗ do primeiro chip.
TeclaComportamento
Tab / Shift + Tab

Percorre os ⊗ dos chips visíveis, o botão +N, o input e o ícone trailing interativo, na ordem do DOM.

EnterConfirma a tag quando triggerOn é enter/both. Nunca submete o formulário.
EspaçoConfirma a tag quando triggerOn é space/both; caso contrário, insere um espaço.
BackspaceCom o rascunho vazio, remove a última tag. Com rascunho, apaga um caractere.
Enter / Espaço no ⊗ ou no +NRemove aquele chip / emite mkOverflowClick.

On this page