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); }
mkTagAddcarregastring[], nãostring. 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.0ou negativo desliga o cortee renderiza todas as tags, com scroll horizontal na faixa.
Ignorar
mkOverflowClickdeixa 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
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
label | string | — | Texto do rótulo exibido acima do campo. Obrigatório. |
tags | string[] | [] | Lista completa de tags. Somente leitura — o componente nunca escreve nela. |
value | string | — | Texto em rascunho: o que está digitado e ainda não virou tag. Não confundir com |
triggerOn | "enter" | "space" | "both" | "enter" | Tecla que confirma o rascunho como tag. |
allowDuplicates | boolean | false | Permite termos repetidos. A deduplicação também vale dentro de um lote colado. |
visibleTags | number | 3 | Máximo de chips renderizados; o excedente vira +N. 0 ou negativo mostra tudo. |
separator | string | RegExp | /(?:\r?\n|,|;|\t)+/ | Quebra o texto digitado ou colado em vários termos. Não inclui espaço. |
pattern | string | RegExp | null | null | Cada termo precisa casar para virar tag. Ancorado implicitamente. Rejeitados voltam ao rascunho. |
type | "text" | "search" | "text" | Tipo do input nativo. |
placeholder | string | — | Placeholder exibido quando não há rascunho digitado. |
supportText | string | — | Texto de suporte abaixo do campo quando não há erro. |
helperText | string | — | Texto exibido no ícone de ajuda ao lado do rótulo. Quando omitido, o ícone não é exibido. |
errorMessage | string | — | Mensagem de erro. Quando definida, o campo entra em estado inválido. |
maxLength | number | — | Limite de caracteres do rascunho. Não exibe contador e não se aplica a texto colado. |
trailingIcon | IconName | — | Ícone Lucide exibido no lado direito do campo. |
trailingIconLabel | string | — | Rótulo acessível do ícone trailing. Quando definido, o ícone vira interativo. |
name | string | — | Atributo name para envio em formulários. |
required | boolean | false | Marca o campo como obrigatório. Valida a quantidade de tags, não o rascunho. |
requiredMessage | string | "This field is required" | Mensagem de validação nativa quando required e sem nenhuma tag. |
disabled | boolean | false | Desabilita o campo e remove o ⊗ dos chips. |
readonly | boolean | false | Campo somente leitura; chips visíveis sem ⊗. |
autocomplete | string | — | Token autocomplete do HTML repassado ao input nativo, para habilitar o autofill do navegador no rascunho. |
Eventos
| Evento | Payload | Descrição |
|---|---|---|
mkTagAdd | string[] | Termos confirmados, com trim(), filtrados e deduplicados. Sempre um array. Não dispara com lote vazio nem em disabled/readonly. |
mkTagRemove | string | Termo 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. |
mkOverflowClick | string[] | As tags escondidas, ao ativar o +N. Dispara também com o campo disabled ou readonly. |
mkInput | string | O rascunho atual, sempre que ele muda. |
mkChange | string | O rascunho, quando mudou e o campo perde o foco. Carrega o texto, não as tags. |
mkFocus | void | O campo recebe foco. |
mkBlur | void | O campo perde o foco, depois do eventual mkTagAdd do rascunho pendente. |
mkTrailingIconClick | void | Í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-invalidearia-describedbysão aplicados conformerequired,errorMessageesupportText.- 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+Ntambém são anunciadas. - Cada ⊗ tem nome acessível único (
Remover {tag}). O+Ntem 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.
| Tecla | Comportamento |
|---|---|
Tab / Shift + Tab | Percorre os ⊗ dos chips visíveis, o botão |
Enter | Confirma a tag quando triggerOn é enter/both. Nunca submete o formulário. |
Espaço | Confirma a tag quando triggerOn é space/both; caso contrário, insere um espaço. |
Backspace | Com o rascunho vazio, remove a última tag. Com rascunho, apaga um caractere. |
Enter / Espaço no ⊗ ou no +N | Remove aquele chip / emite mkOverflowClick. |
Input OTP
Campo de código de uso único (OTP) com slots individuais, avanço automático de foco e suporte a colar.
Mentions
Campo de texto onde `@` e `#` abrem um dropdown, e a option escolhida vira uma tag indivisível dentro do texto. O `mk-mentions` não filtra e não busca — ele detecta o gatilho, emite a query, e renderiza exatamente o que você devolver.