Componente
Input
Campi di testo .italia: etichetta sopra, bordo ardesia, testo di aiuto e messaggi di validazione legati con aria-describedby. daisyUI input, textarea, floating-label e validator.
- Riferimento
<it-input>- Classi
ita-fieldita-labelita-requiredita-hintita-inputita-textareaita-input-smita-input-lgita-textarea-smita-textarea-lgita-input-plaintextita-input-affixita-floating-labelita-validita-invalidita-feedbackita-validateita-validate-hint- Basato su (daisyUI)
inputtextareafloating-labelvalidatorjoin- Solo CSS
- Il bordo ardesia (contrasto 3:1) è una regola di @italia-tailwind/css nello stesso sotto-layer di daisyUI, quindi input-error, validator e :focus lo sostituiscono. La validazione nativa usa :user-invalid tramite daisyUI validator: il messaggio compare solo dopo che l'utente ha modificato il campo. Mostra/nascondi password e contatore di caratteri richiedono JavaScript e non sono inclusi: il campo password resta type=password.
- Storybook
- Apri le storie di Input
Esempio base
Useremo questo indirizzo solo per risponderti.
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label for="input-1" class="ita-label">Nome</label>
<input type="text" id="input-1" class="ita-input" placeholder="Mario" autocomplete="given-name">
</div>
<div class="ita-field">
<label for="input-2" class="ita-label">Cognome</label>
<input type="text" id="input-2" class="ita-input" placeholder="Rossi" autocomplete="family-name">
</div>
<div class="ita-field">
<label for="input-3" class="ita-label">Indirizzo email</label>
<input type="email" id="input-3" class="ita-input" placeholder="nome@esempio.it" aria-describedby="input-3-hint">
<p id="input-3-hint" class="ita-hint">Useremo questo indirizzo solo per risponderti.</p>
</div>
<div class="ita-field">
<label for="input-4" class="ita-label">Telefono</label>
<input type="tel" id="input-4" class="ita-input" placeholder="+39 06 1234567" autocomplete="tel">
</div>
</div>Tipologie di campo
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label for="input-5" class="ita-label">Password</label>
<input type="password" id="input-5" class="ita-input" autocomplete="current-password">
</div>
<div class="ita-field">
<label for="input-6" class="ita-label">Numero</label>
<input type="number" id="input-6" class="ita-input" value="3" min="0" max="10" step="1">
</div>
<div class="ita-field">
<label for="input-7" class="ita-label">Data</label>
<input type="date" id="input-7" class="ita-input">
</div>
<div class="ita-field">
<label for="input-8" class="ita-label">Ora</label>
<input type="time" id="input-8" class="ita-input">
</div>
</div>Area di testo
Massimo 500 caratteri.
Mostra il codice HTMLNascondi il codice HTML
<div class="ita-field">
<label for="input-9" class="ita-label">Messaggio</label>
<textarea id="input-9" class="ita-textarea" placeholder="Scrivi qui la tua richiesta" rows="4" aria-describedby="input-9-hint"></textarea>
<p id="input-9-hint" class="ita-hint">Massimo 500 caratteri.</p>
</div>Disabilitato e sola lettura
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label for="input-10" class="ita-label">Campo disabilitato</label>
<input type="text" id="input-10" class="ita-input" value="Non modificabile" disabled>
</div>
<div class="ita-field">
<label for="input-11" class="ita-label">Campo in sola lettura</label>
<input type="text" id="input-11" class="ita-input" value="RSSMRA80A01H501U" readonly>
</div>
<div class="ita-field">
<label for="input-12" class="ita-label">Testo semplice</label>
<input type="text" id="input-12" class="ita-input ita-input-plaintext" value="mario.rossi@esempio.it" readonly>
</div>
</div>Dimensioni
Mostra il codice HTMLNascondi il codice HTML
<div class="flex flex-col gap-6">
<div class="ita-field">
<label for="input-13" class="ita-label">Campo piccolo</label>
<input type="text" id="input-13" class="ita-input ita-input-sm" placeholder="input-sm">
</div>
<div class="ita-field">
<label for="input-14" class="ita-label">Campo standard</label>
<input type="text" id="input-14" class="ita-input" placeholder="44px (--size-field del tema)">
</div>
<div class="ita-field">
<label for="input-15" class="ita-label">Campo grande</label>
<input type="text" id="input-15" class="ita-input ita-input-lg" placeholder="input-lg">
</div>
</div>Icone e unità
Con un'icona o un'unità daisyUI sposta la classe input sul contenitore: il campo interno perde il bordo.
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label for="input-16" class="ita-label">Cerca</label>
<div class="ita-input"><svg class="shrink-0 fill-current" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M21.9,21.1L16,15.3c1.3-1.5,2-3.4,2-5.3c0-4.4-3.6-8-8-8s-8,3.6-8,8s3.6,8,8,8c1.9,0,3.8-0.7,5.3-2l5.8,5.9L21.9,21.1z M10,17c-3.9,0-7-3.1-7-7s3.1-7,7-7s7,3.1,7,7S13.9,17,10,17z" /></svg><input type="search" id="input-16" placeholder="Cerca nel sito"></div>
</div>
<div class="ita-field">
<label for="input-17" class="ita-label">Email</label>
<div class="ita-input"><svg class="shrink-0 fill-current" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M20.5,5h-17C2.7,5,2,5.7,2,6.5v11C2,18.3,2.7,19,3.5,19h17c0.8,0,1.5-0.7,1.5-1.5v-11C22,5.7,21.3,5,20.5,5z M20.2,6 l-7.1,7.2c-0.6,0.6-1.6,0.6-2.2,0L3.8,6H20.2z M3,17.3V6.6L8.3,12L3,17.3z M3.7,18L9,12.7l1.2,1.2c1,0.9,2.6,0.9,3.6,0l1.2-1.2l0,0 l5.3,5.3H3.7z M15.7,12L21,6.6v10.7L15.7,12z" /></svg><input type="email" id="input-17" placeholder="nome@esempio.it"></div>
</div>
<div class="ita-field">
<label for="input-18" class="ita-label">Importo</label>
<div class="ita-input"><span class="ita-input-affix" aria-hidden="true">€</span><input type="number" id="input-18" placeholder="0,00" step="0.01"></div>
</div>
<div class="ita-field">
<label for="input-19" class="ita-label">Sconto</label>
<div class="ita-input"><input type="number" id="input-19" value="10" min="0" max="100"><span class="ita-input-affix" aria-hidden="true">%</span></div>
</div>
</div>Con pulsante
Mostra il codice HTMLNascondi il codice HTML
<div class="ita-field">
<label for="input-20" class="sr-only">Cerca un servizio</label>
<div class="join w-full"><div class="join-item ita-input"><svg class="shrink-0 fill-current" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M21.9,21.1L16,15.3c1.3-1.5,2-3.4,2-5.3c0-4.4-3.6-8-8-8s-8,3.6-8,8s3.6,8,8,8c1.9,0,3.8-0.7,5.3-2l5.8,5.9L21.9,21.1z M10,17c-3.9,0-7-3.1-7-7s3.1-7,7-7s7,3.1,7,7S13.9,17,10,17z" /></svg><input type="search" id="input-20" placeholder="Cerca un servizio"></div><button type="submit" class="join-item ita-btn ita-btn-primary">Cerca</button></div>
</div>Validazione dal server
Lo stato arriva già calcolato: input-error / input-success più un messaggio legato al campo.
Codice fiscale corretto
Inserisci un indirizzo email valido
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label for="input-21" class="ita-label">Codice fiscale</label>
<input type="text" id="input-21" class="ita-input ita-valid" value="RSSMRA80A01H501U" aria-describedby="input-21-feedback">
<p id="input-21-feedback" class="ita-feedback ita-feedback-valid"><svg class="shrink-0 fill-current" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M17.1,7.9l0.7,0.7L10,16.2l-4.7-4.6L6,10.9l4,3.9L17.1,7.9z M22,12c0,5.5-4.5,10-10,10S2,17.5,2,12S6.5,2,12,2S22,6.5,22,12z M21,12c0-5-4-9-9-9s-9,4-9,9s4,9,9,9S21,17,21,12z" /></svg><span>Codice fiscale corretto</span></p>
</div>
<div class="ita-field">
<label for="input-22" class="ita-label">Email <span class="ita-required" aria-hidden="true">*</span></label>
<input type="email" id="input-22" class="ita-input ita-invalid" value="mario.rossi@" required aria-invalid="true" aria-describedby="input-22-feedback">
<p id="input-22-feedback" class="ita-feedback ita-feedback-invalid"><svg class="shrink-0 fill-current" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M11.5,14.2V5.7h1.2v8.5H11.5z M11.4,18.3h1.2v-1.8h-1.2V18.3z M22,7.9v8.3L16.1,22H7.9L2,16.2V7.9L7.9,2h8.2L22,7.9z M21,8.3L15.7,3H8.3L3,8.3v7.5L8.3,21h7.4l5.3-5.2V8.3z" /></svg><span>Inserisci un indirizzo email valido</span></p>
</div>
</div>Validazione nativa
daisyUI validator: scrivi un valore e spostati sul campo successivo. Il messaggio appare solo dopo l'interazione (:user-invalid).
Inserisci un indirizzo email valido
Il CAP è di 5 cifre
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label for="input-23" class="ita-label">Email <span class="ita-required" aria-hidden="true">*</span></label>
<input type="email" id="input-23" class="ita-input ita-validate" placeholder="nome@esempio.it" required aria-describedby="input-23-vhint">
<p id="input-23-vhint" class="ita-validate-hint">Inserisci un indirizzo email valido</p>
</div>
<div class="ita-field">
<label for="input-24" class="ita-label">CAP <span class="ita-required" aria-hidden="true">*</span></label>
<input type="text" id="input-24" class="ita-input ita-validate" placeholder="00100" pattern="[0-9]{5}" maxlength="5" required aria-describedby="input-24-vhint">
<p id="input-24-vhint" class="ita-validate-hint">Il CAP è di 5 cifre</p>
</div>
</div>Etichetta flottante
daisyUI floating-label: l'etichetta sale sopra il bordo quando il campo riceve il focus.
Mostra il codice HTMLNascondi il codice HTML
<div class="grid gap-6 md:grid-cols-2">
<div class="ita-field">
<label class="ita-floating-label"><input type="text" id="input-25" class="ita-input" placeholder="Nome"><span>Nome</span></label>
</div>
<div class="ita-field">
<label class="ita-floating-label"><input type="text" id="input-26" class="ita-input ita-input-lg" placeholder="Città"><span>Città</span></label>
</div>
</div>Con JavaScript (opzionale)
La ricetta è solo CSS e funziona così com'è. Questi frammenti non sono inclusi nel pacchetto: mostrano come aggiungere il comportamento che richiede uno script, in JavaScript semplice o in React.
Mostra / nascondi passwordjs
Aggiunge un pulsante accanto ai campi password; aria-pressed dice lo stato.
document.querySelectorAll("input[type=password]").forEach((field) => {
const btn = document.createElement("button");
btn.type = "button";
btn.className = "join-item ita-btn ita-btn-ghost ita-btn-xs";
btn.textContent = "Mostra";
btn.setAttribute("aria-pressed", "false");
btn.setAttribute("aria-controls", field.id);
btn.addEventListener("click", () => {
const show = field.type === "password";
field.type = show ? "text" : "password";
btn.textContent = show ? "Nascondi" : "Mostra";
btn.setAttribute("aria-pressed", String(show));
});
field.after(btn);
});Contatore di caratterijs
Per i campi con maxlength: il conteggio è annunciato con calma (aria-live=polite).
document.querySelectorAll("textarea[maxlength], input[maxlength]").forEach((field) => {
const out = document.createElement("p");
out.className = "mt-1 text-sm text-base-content/70";
out.setAttribute("aria-live", "polite");
const max = field.maxLength;
const update = () => (out.textContent = "Caratteri rimanenti: " + (max - field.value.length));
field.addEventListener("input", update);
field.after(out);
update();
});Password in Reacttsx
import { useId, useState } from "react";
export function PasswordInput({ label }: { label: string }) {
const id = useId();
const [show, setShow] = useState(false);
return (
<div className="w-full max-w-md">
<label htmlFor={id} className="mb-1 block font-semibold">{label}</label>
<div className="join w-full">
<input id={id} type={show ? "text" : "password"} autoComplete="current-password" className="join-item ita-input" />
<button type="button" className="join-item ita-btn" aria-pressed={show} aria-controls={id} onClick={() => setShow(!show)}>
{show ? "Nascondi" : "Mostra"}
</button>
</div>
</div>
);
}