Input
Campo de texto de uma linha ou multilinha (Textarea), com rótulo, texto de ajuda e validação.
'use client';
import { TextField } from '@/components/ui/input';
export default function InputDemo() {
return (
<TextField
name="email"
type="email"
label="E-mail"
placeholder="voce@suaempresa.com.br"
description="Enviaremos o orçamento para este endereço."
className="w-full max-w-sm"
/>
);
}Instalação
npx shadcn@latest add @lenstech/inputUso
import { TextField } from "@/components/ui/input"<TextField name="email" type="email" label="E-mail" isRequired />O arquivo exporta três componentes:
TextField— campo completo (rótulo + input + descrição + erro). É o que você usa na maior parte do tempo.InputeTextarea— só a caixa de texto, para composição manual ou uso solto (comaria-label).
onChange recebe o texto, não o evento
No React Aria, onChange de TextField entrega a string digitada: onChange={setNome}. Não use
e.target.value.
Exemplos
Tipos
type aceita text, email, tel, url, password e search. Combine com autoComplete para o navegador
preencher os dados do usuário.
'use client';
import { TextField } from '@/components/ui/input';
export default function InputTypes() {
return (
<div className="flex w-full max-w-sm flex-col gap-6">
<TextField label="E-mail" type="email" autoComplete="email" placeholder="voce@suaempresa.com.br" />
<TextField label="WhatsApp" type="tel" autoComplete="tel" placeholder="(11) 91234-5678" />
<TextField label="Site atual" type="url" placeholder="https://" />
<TextField label="Senha" type="password" description="Mínimo de 8 caracteres." />
</div>
);
}Textarea
Use multiline para trocar o input por um Textarea, que cresce conforme o conteúdo.
'use client';
import { TextField } from '@/components/ui/input';
export default function InputTextarea() {
return (
<TextField
name="mensagem"
label="Conte sobre o seu negócio"
multiline
rows={4}
placeholder="Ex.: Tenho uma clínica odontológica e quero agendamento online."
description="Quanto mais detalhes, mais preciso o orçamento."
className="w-full max-w-sm"
/>
);
}Validação
Validação nativa (isRequired, type="email", minLength, pattern…) e customizada com validate. Os erros
aparecem ao enviar o Form. Tente enviar vazio.
'use client';
import { Button } from '@/components/ui/button';
import { Form } from '@/components/ui/form';
import { TextField } from '@/components/ui/input';
export default function InputValidation() {
return (
<Form onSubmit={(e) => e.preventDefault()} className="w-full max-w-sm">
<TextField
name="email"
type="email"
label="E-mail"
isRequired
errorMessage={({ validationDetails }) =>
validationDetails.valueMissing ? 'Informe seu e-mail.' : 'Digite um e-mail válido.'
}
/>
<TextField
name="cep"
label="CEP"
placeholder="00000-000"
validate={(valor) =>
valor && !/^\d{5}-?\d{3}$/.test(valor) ? 'Digite um CEP válido, ex.: 01310-100.' : null
}
/>
<Button type="submit" className="self-start">
Validar
</Button>
</Form>
);
}isInvalid ou validate?
validate devolve a mensagem de erro (ou null) e integra com o envio do formulário. Use isInvalid +
errorMessage apenas quando a validação acontece fora do campo (por exemplo, um estado da sua página). Erros
vindos do servidor vão em validationErrors no Form.
Desabilitado e somente leitura
'use client';
import { TextField } from '@/components/ui/input';
export default function InputDisabled() {
return (
<div className="flex w-full max-w-sm flex-col gap-6">
<TextField label="Razão social" defaultValue="Oficina do Zé Ltda." isDisabled />
<TextField
label="Código do cliente"
defaultValue="LT-000482"
isReadOnly
description="Somente leitura: pode ser selecionado e copiado, mas não editado."
/>
</div>
);
}Controlado
Use value + onChange quando precisar reagir ao que é digitado — aqui, um contador de caracteres.
'use client';
import { useState } from 'react';
import { TextField } from '@/components/ui/input';
const LIMITE = 160;
export default function InputControlled() {
const [bio, setBio] = useState('');
return (
<TextField
label="Descrição curta"
multiline
rows={3}
value={bio}
onChange={setBio}
maxLength={LIMITE}
placeholder="Pães artesanais de fermentação natural, direto do forno."
description={`${bio.length}/${LIMITE} caracteres — aparece no Google e nas redes sociais.`}
className="w-full max-w-sm"
/>
);
}Composição manual
Passe filhos ao TextField para montar o layout com as peças do Field.
'use client';
import { FieldDescription, FieldError, Label } from '@/components/ui/field';
import { Input, Textarea, TextField } from '@/components/ui/input';
export default function InputComposed() {
return (
<div className="flex w-full max-w-sm flex-col gap-6">
<TextField isRequired>
<Label>
Nome do responsável <span className="text-destructive">*</span>
</Label>
<Input placeholder="Dra. Ana Souza" />
<FieldDescription>Quem vai aprovar o layout.</FieldDescription>
<FieldError>Informe o nome do responsável.</FieldError>
</TextField>
<TextField>
<Label>Observações</Label>
<Textarea placeholder="Horários preferidos para contato, referências…" />
</TextField>
</div>
);
}Quando usar
- Use para textos livres: nome, e-mail, telefone, mensagem.
- Não use para números com incremento, preços ou quantidades — use
NumberField. - Não use para datas — use
DateFieldouDatePicker. - Para escolher entre opções conhecidas, use
SelectouCombobox; para busca,SearchField.
API
TextField
Aceita todas as props do TextField do React Aria, mais:
Prop
Type
Input e Textarea
Aceitam todas as props de Input e TextArea do React Aria (e,
portanto, os atributos HTML de <input> e <textarea>).