Pular para o conteúdo

Input

templates/components/Input

O Input é o controle de entrada de texto de linha única: sua natureza é capturar, formatar, restringir e validar o que a pessoa DIGITA. Portanto todo enriquecedor aqui assiste, restringe, formata, valida ou anota o valor digitado — nunca reestiliza o campo. A base já traz o mecanismo de composição InputGroup (Addon/Button/Text), que permite grudar conteúdo aditivo nas bordas do campo sem tocar no visual congelado.

Base congelada

Your API key is encrypted and stored securely.

Conteúdo

Máscara de formatação

Formata o valor em tempo real…

Formata o valor em tempo real enquanto digita, inserindo separadores e limitando o conjunto de caracteres; guarda o valor cru para o submit.

Afixo (prefixo/sufixo)

Rótulo fixo não-editável grudado ao campo…

Rótulo fixo não-editável grudado ao campo via InputGroup:Addon (ex.: 'R$', 'https://', '@empresa.com', 'kg'), à esquerda ou à direita — puramente aditivo. posicionável

Senha: mostrar/ocultar

Para type=password, botão de olho no…

Para type=password, botão de olho no fim alterna entre caracteres ocultos e visíveis, sem mudar o layout do campo.

Contador de caracteres

Exibe 'N / limite', aplica maxlength…

Exibe 'N / limite', aplica maxlength e avisa ao se aproximar do limite; colocável no fim (inline-end) ou abaixo (block-end). posicionável

Comportamento

Ícone contextual

Ícone lucide indicativo (não clicável) dentro…

Ícone lucide indicativo (não clicável) dentro de um Addon, no início ou fim do campo, para dar contexto (busca, e-mail, cadeado, calendário). posicionável

Botão limpar

Botão ghost 'x' que aparece quando…

Botão ghost 'x' que aparece quando o campo tem conteúdo e o esvazia em um clique, devolvendo o foco ao input (InputGroup:Button, fim).

Validação funcional

Valida no blur/input e, ao falhar,…

Valida no blur/input e, ao falhar, seta aria-invalid (cujo visual JÁ é congelado na base) e mostra mensagem inline — o enricher decide só o QUANDO e o texto, nunca o estilo.

Sugestões (autocompletar)

Lista de valores para sugerir enquanto…

Lista de valores para sugerir enquanto digita via datalist nativo; o popup é do navegador e não toca no visual da base.

Restrição de teclado (inputmode)

Define inputmode/type semântico para o teclado…

Define inputmode/type semântico para o teclado mobile correto e bloqueia teclas fora do conjunto (ex.: só dígitos), sem qualquer mudança visual.
Código gerado

Cole no Claude Code — ele acerta de primeira.

Input (UI) — Design System (Symfony UX Toolkit / shadcn)

BASE CONGELADA (não mude por instância): CONGELADO: o próprio <input> — altura h-8, largura w-full, cantos rounded-lg, borda border-input, fundo bg-transparent (dark bg-input/30), padding px-2.5 py-1, tipografia text-base/md:text-sm, transição de cor e placeholder text-muted-foreground. Estados visuais imutáveis: foco (focus-visible: border-ring + ring-3 ring-ring/50), INVÁLIDO (aria-invalid: border-destructive + ring-destructive — o "look de erro" já vive na base) e desabilitado (opacity-50, cursor-not-allowed, bg-input/50). a11y congelada: outline-none com anel de foco visível, semântica aria-invalid, data-slot="input" e passthrough de {{ attributes }}. Mecanismo de composição congelado: o sistema InputGroup — Addon (align inline-start/end e block-start/end, texto muted-foreground, ícone size-4, raio herdado), Button (ghost, size xs, raio calc(var(--radius)-3px)) e Text — é o ÚNICO caminho pelo qual conteúdo aditivo entra nas bordas sem alterar fonte/cor/cantos/espaçamento da base.

USO: <twig:Input />

CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Máscara de formatação: Formata o valor em tempo real enquanto digita, inserindo separadores e limitando o conjunto de caracteres; guarda o valor cru para o submit. [select → CPF / CNPJ / CPF/CNPJ (auto) / Telefone/Celular / CEP / Data (dd/mm/aaaa) / Moeda (R$) / Percentual / Cartão de crédito / Placa (Mercosul)]- Afixo (prefixo/sufixo): Rótulo fixo não-editável grudado ao campo via InputGroup:Addon (ex.: 'R$', 'https://', '@empresa.com', 'kg'), à esquerda ou à direita — puramente aditivo. [text]- Ícone contextual: Ícone lucide indicativo (não clicável) dentro de um Addon, no início ou fim do campo, para dar contexto (busca, e-mail, cadeado, calendário). [select → search / mail / lock / user / calendar / phone / map-pin / dollar-sign]- Botão limpar: Botão ghost 'x' que aparece quando o campo tem conteúdo e o esvazia em um clique, devolvendo o foco ao input (InputGroup:Button, fim). [toggle]- Senha: mostrar/ocultar: Para type=password, botão de olho no fim alterna entre caracteres ocultos e visíveis, sem mudar o layout do campo. [toggle]- Contador de caracteres: Exibe 'N / limite', aplica maxlength e avisa ao se aproximar do limite; colocável no fim (inline-end) ou abaixo (block-end). [number]- Validação funcional: Valida no blur/input e, ao falhar, seta aria-invalid (cujo visual JÁ é congelado na base) e mostra mensagem inline — o enricher decide só o QUANDO e o texto, nunca o estilo. [select → Obrigatório / E-mail / URL / Número / CPF/CNPJ / Igual a outro campo / Regex custom]- Sugestões (autocompletar): Lista de valores para sugerir enquanto digita via datalist nativo; o popup é do navegador e não toca no visual da base. [text]- Restrição de teclado (inputmode): Define inputmode/type semântico para o teclado mobile correto e bloqueia teclas fora do conjunto (ex.: só dígitos), sem qualquer mudança visual. [select → Texto / Numérico / Decimal / Telefone / E-mail / URL / Busca]FAÇA:
- Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.
- Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.
- Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}.
NÃO FAÇA:
- Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.
- Não crie variante/fork para a mesma coisa — existe UMA base por componente.
- Não reimplemente o componente nem adicione toolchain Node.
TESTE ANTES DE MUDAR: "é função ou é base?" — função = capacidade opt-in; base = mude o token na fonte única (assets/styles/app.css), para todos.

A11Y (herdada da base): Estados visuais imutáveis: foco (focus-visible: border-ring + ring-3 ring-ring/50), INVÁLIDO (aria-invalid: border-destructive + ring-destructive — o "look de erro" já vive na base) e desabilitado (opacity-50, cursor-not-allowed, bg-input/50). a11y congelada: outline-none com anel de foco visível, semântica aria-invalid, data-slot="input" e passthrough de {{ attributes }}

Via MCP: tool get_component com {"id": "input"} · list_capabilities("input").

Spec crua: config/ds-specs/input.json · Conectar o MCP.

Spec machine-readable (JSON)

{
    "$schema_version": "1.0",
    "id": "input",
    "component": "Input",
    "eixo": "ui",
    "particularidade": "O Input é o controle de entrada de texto de linha única: sua natureza é capturar, formatar, restringir e validar o que a pessoa DIGITA. Portanto todo enriquecedor aqui assiste, restringe, formata, valida ou anota o valor digitado — nunca reestiliza o campo. A base já traz o mecanismo de composição InputGroup (Addon/Button/Text), que permite grudar conteúdo aditivo nas bordas do campo sem tocar no visual congelado.",
    "base_congelada": "CONGELADO: o próprio <input> — altura h-8, largura w-full, cantos rounded-lg, borda border-input, fundo bg-transparent (dark bg-input/30), padding px-2.5 py-1, tipografia text-base/md:text-sm, transição de cor e placeholder text-muted-foreground. Estados visuais imutáveis: foco (focus-visible: border-ring + ring-3 ring-ring/50), INVÁLIDO (aria-invalid: border-destructive + ring-destructive — o \"look de erro\" já vive na base) e desabilitado (opacity-50, cursor-not-allowed, bg-input/50). a11y congelada: outline-none com anel de foco visível, semântica aria-invalid, data-slot=\"input\" e passthrough de {{ attributes }}. Mecanismo de composição congelado: o sistema InputGroup — Addon (align inline-start/end e block-start/end, texto muted-foreground, ícone size-4, raio herdado), Button (ghost, size xs, raio calc(var(--radius)-3px)) e Text — é o ÚNICO caminho pelo qual conteúdo aditivo entra nas bordas sem alterar fonte/cor/cantos/espaçamento da base.",
    "props": [],
    "capacidades": [
        {
            "id": "m-scara-de-formata-o",
            "nome": "Máscara de formatação",
            "descricao": "Formata o valor em tempo real enquanto digita, inserindo separadores e limitando o conjunto de caracteres; guarda o valor cru para o submit.",
            "controle": "select",
            "opcoes": [
                "CPF",
                "CNPJ",
                "CPF/CNPJ (auto)",
                "Telefone/Celular",
                "CEP",
                "Data (dd/mm/aaaa)",
                "Moeda (R$)",
                "Percentual",
                "Cartão de crédito",
                "Placa (Mercosul)"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "afixo-prefixo-sufixo",
            "nome": "Afixo (prefixo/sufixo)",
            "descricao": "Rótulo fixo não-editável grudado ao campo via InputGroup:Addon (ex.: 'R$', 'https://', '@empresa.com', 'kg'), à esquerda ou à direita — puramente aditivo.",
            "controle": "text",
            "opcoes": [],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "cone-contextual",
            "nome": "Ícone contextual",
            "descricao": "Ícone lucide indicativo (não clicável) dentro de um Addon, no início ou fim do campo, para dar contexto (busca, e-mail, cadeado, calendário).",
            "controle": "select",
            "opcoes": [
                "search",
                "mail",
                "lock",
                "user",
                "calendar",
                "phone",
                "map-pin",
                "dollar-sign"
            ],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "bot-o-limpar",
            "nome": "Botão limpar",
            "descricao": "Botão ghost 'x' que aparece quando o campo tem conteúdo e o esvazia em um clique, devolvendo o foco ao input (InputGroup:Button, fim).",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "senha-mostrar-ocultar",
            "nome": "Senha: mostrar/ocultar",
            "descricao": "Para type=password, botão de olho no fim alterna entre caracteres ocultos e visíveis, sem mudar o layout do campo.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "contador-de-caracteres",
            "nome": "Contador de caracteres",
            "descricao": "Exibe 'N / limite', aplica maxlength e avisa ao se aproximar do limite; colocável no fim (inline-end) ou abaixo (block-end).",
            "controle": "number",
            "opcoes": [],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "valida-o-funcional",
            "nome": "Validação funcional",
            "descricao": "Valida no blur/input e, ao falhar, seta aria-invalid (cujo visual JÁ é congelado na base) e mostra mensagem inline — o enricher decide só o QUANDO e o texto, nunca o estilo.",
            "controle": "select",
            "opcoes": [
                "Obrigatório",
                "E-mail",
                "URL",
                "Número",
                "CPF/CNPJ",
                "Igual a outro campo",
                "Regex custom"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "sugest-es-autocompletar",
            "nome": "Sugestões (autocompletar)",
            "descricao": "Lista de valores para sugerir enquanto digita via datalist nativo; o popup é do navegador e não toca no visual da base.",
            "controle": "text",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "restri-o-de-teclado-inputmode",
            "nome": "Restrição de teclado (inputmode)",
            "descricao": "Define inputmode/type semântico para o teclado mobile correto e bloqueia teclas fora do conjunto (ex.: só dígitos), sem qualquer mudança visual.",
            "controle": "select",
            "opcoes": [
                "Texto",
                "Numérico",
                "Decimal",
                "Telefone",
                "E-mail",
                "URL",
                "Busca"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/input; comportamento via controller Stimulus. Não altera a base."
        }
    ],
    "snippet_uso": "<twig:Input />",
    "exemplo_demo": "<div class=\"*:max-w-xs w-full justify-center flex\">\n    <twig:Field>\n        <twig:Field:Label for=\"input-demo-api-key\">API Key</twig:Field:Label>\n        <twig:Input id=\"input-demo-api-key\" type=\"password\" placeholder=\"sk-...\" />\n        <twig:Field:Description>Your API key is encrypted and stored securely.</twig:Field:Description>\n    </twig:Field>\n</div>",
    "regras": {
        "faca": [
            "Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.",
            "Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.",
            "Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}."
        ],
        "nao_faca": [
            "Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.",
            "Não crie variante/fork para a mesma coisa — existe UMA base por componente.",
            "Não reimplemente o componente nem adicione toolchain Node."
        ]
    },
    "a11y": "Estados visuais imutáveis: foco (focus-visible: border-ring + ring-3 ring-ring/50), INVÁLIDO (aria-invalid: border-destructive + ring-destructive — o \"look de erro\" já vive na base) e desabilitado (opacity-50, cursor-not-allowed, bg-input/50). a11y congelada: outline-none com anel de foco visível, semântica aria-invalid, data-slot=\"input\" e passthrough de {{ attributes }}",
    "mcp": {
        "tool": "get_component",
        "args": {
            "id": "input"
        }
    },
    "props_nota": "Sem props próprias declaradas: a base repassa atributos nativos via {{ attributes }} (id, name, type, value, aria-*, data-*). Props específicas, quando existem, ficam nos subcomponentes."
}