Vai al contenuto

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 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 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 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 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 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 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 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 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 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 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>
  );
}