<div class="rtds-input-field rtds-gap-1 rtds-input-field--disabled ">
<label for="inputId" class="rtds-input-field__label">
Text label
</label>
<div class="rtds-input">
<input id="inputId" class="rtds-text-sm rtds-input-placeholder" type="text" disabled>
</div>
</div>
<div class="rtds-input-field{% if gap %} {{ gap }}{% else %} rtds-gap-1{% endif %}{% if classes %} {{ classes }}{% endif %}{% if inputDisabled %} rtds-input-field--disabled{% endif %} {% if inputHasError %} has-error{% endif %}">
<label for="{{ inputId }}" class="rtds-input-field__label{% if hiddenLabel %} rtds-sr-only{% endif %}{% if labelClasses %} {{ labelClasses }}{% endif %}">
{{ label }}
{% if inputRequired %}
<abbr class="rtds-font-bold rtds-no-underline" title="obbligatorio">*</abbr>
{% endif %}
</label>
{% block input %}
{% render '@input', { id: inputId, shortLabel: inputShortLabel, padding: inputPadding, border: inputBorder, radius: inputRadius, classes: inputClasses, type: inputType, placeholder: inputPlaceholder, iconPlaceholder: inputIconPlaceholder, fieldRequired: inputRequired, autocomplete: inputAutocomplete, ariaDescribedBy: inputAriaDescribedBy, hasErrorControl: inputHasErrorControl, ariaInvalid: inputAriaInvalid, iconAlert: inputIconAlert, hasError: inputHasError, disabled: inputDisabled, readonly: inputReadonly }, true %}
{% endblock %}
{% if inputRequired or inputAriaDescribedBy or inputHasErrorControl %}
<span class="rtds-input-field__hint">
{% if inputRequired or inputHasErrorControl %}
<span class="rtds-input-field__error" id="{{ inputId }}Error" aria-live="assertive">
{{ errorDescription }}
</span>
{% endif %}
{% if inputDescription %}
<span class="rtds-input-field__description" id="{{ inputAriaDescribedBy }}">
{{ inputDescription }}
</span>
{% endif %}
</span>
{% endif %}
</div>
{
"label": "Text label",
"inputId": "inputId",
"inputType": "text",
"inputDisabled": true
}
/**
* INPUT FIELD
*
*/
.rtds-input-field {
display: grid;
align-content: flex-start;
}
.rtds-input-field__label {
display: block;
font-size: var(--fontsize-text-sm);
color: var(--color-content-03);
font-weight: 700;
}
legend:where(.rtds-input-field__label) {
margin-bottom: var(--spacing-1);
}
.rtds-input-field__hint {
display: grid;
}
.rtds-input-field__error {
font-size: var(--fontsize-text-sm);
font-weight: 500;
color: var(--color-content-error);
}
.rtds-input-field__description {
font-size: var(--fontsize-text-sm);
font-weight: 500;
color: var(--color-content-03);
}
.rtds-input-field.has-error input {
border-width: 2px;
border-color: var(--color-error-dark);
}
/* DISABLED STATE */
:where(.rtds-input-field--disabled) .rtds-input-field__label,
:where(.rtds-input-field--disabled) .rtds-input-field__description {
color: var(--color-content-disabled);
}
/* INPUT FIELD INLINE */
.rtds-field-inline {
display: flex;
align-items: center;
gap: var(--spacing-2);
}
.rtds-field-inline .rtds-input,
.rtds-field-inline .rtds-select {
flex: 1 1 0%;
}
/**
* INPUT FIELD
*
*/
@layer components {
.rtds-input-field {
@apply rtds-grid rtds-content-start;
}
.rtds-input-field__label {
@apply rtds-block rtds-text-sm rtds-font-bold rtds-content-03;
}
legend:where(.rtds-input-field__label) {
@apply rtds-mb-1;
}
.rtds-input-field__hint {
@apply rtds-grid;
}
.rtds-input-field__error {
@apply rtds-text-sm rtds-font-medium rtds-content-error;
}
.rtds-input-field__description {
@apply rtds-text-sm rtds-font-medium rtds-content-03;
}
.rtds-input-field.has-error input {
@apply rtds-border-2 rtds-border-error-dark;
}
/* DISABLED STATE */
:where(.rtds-input-field--disabled) .rtds-input-field__label,
:where(.rtds-input-field--disabled) .rtds-input-field__description {
color: var(--color-content-disabled);
}
/* INPUT FIELD INLINE */
.rtds-field-inline {
@apply rtds-flex rtds-items-center rtds-gap-2;
}
.rtds-field-inline .rtds-input,
.rtds-field-inline .rtds-select {
@apply rtds-flex-1;
}
}
window.addEventListener('load', function () {
var fields = document.querySelectorAll('.rtds-input-field--password');
if (fields.length === 0) return;
fields.forEach(function (field) {
var input = field.querySelector('input[type="password"], input[type="text"]');
var btn = field.querySelector('.rtds-input-field__toggle-btn');
var liveRegion = field.querySelector('[aria-live][aria-atomic]');
var icon = btn ? btn.querySelector('use') : null;
if (!input || !btn) return;
btn.addEventListener('click', function () {
var isVisible = input.type === 'text';
input.type = isVisible ? 'password' : 'text';
btn.setAttribute('aria-pressed', isVisible ? 'false' : 'true');
if (liveRegion) {
liveRegion.textContent = isVisible ? 'Password nascosta' : 'Password visibile';
}
if (icon) {
var currentHref = icon.getAttribute('href') || '';
var base = currentHref.replace(/#.*$/, '');
icon.setAttribute('href', base + (isVisible ? '#outline--eye' : '#outline--eye-slash'));
}
});
});
});
Componente composito per campi di input. Include un componente input personalizzabile con supporto completo per l’accessibilità e la validazione.
Il componente Input Field gestisce:
default: Input di tipo testo basesearch: Input di ricerca con icona di lente d’ingrandimentohas-error-markup: Input con markup per la gestione degli erroriis-required: Input obbligatoriohas-description: Input con descrizionehas-error: Input con stato di errorehas-error-and-description: Input con stato di errore e descrizionedisabled: Campo disabilitato — label e campo visivamente mutedreadonly: Campo non modificabile — nessuno stile aggiuntivo, label invariatapassword: Campo password con toggle mostra/nascondi accessibile — usa il template input-field--password.njkContesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context
.config.ymlusati durante lo sviluppo nella libreria. Non descrive attributi HTML o proprietà da usare nei temi, CMS o ambienti di implementazione: per quello, fare riferimento alla sezione Esempi di utilizzo.
label (stringa, obbligatorio): Testo dell’etichetta del campoinputId (stringa, obbligatorio): ID univoco per il campo inputlabelClasses (stringa, opzionale): Classi CSS aggiuntive per l’etichettahiddenLabel (booleano, opzionale): Se true, nasconde visivamente l’etichetta (rimane disponibile per screen reader)inputShortLabel (stringa, opzionale): Versione abbreviata dell’etichetta per la gestione degli errori JavaScriptgap (stringa, opzionale): Personalizzazione dello spazio interno (default: gap-1)inputPadding (stringa, opzionale): Override del padding dell’inputinputBorder (stringa, opzionale): Override del bordo dell’inputinputRadius (stringa, opzionale): Override del border-radius dell’inputinputClasses (stringa, opzionale): Classi CSS aggiuntive per l’inputinputType (stringa, opzionale): Tipo di input (text, tel, email, search, ecc.)inputPlaceholder (stringa, opzionale): Testo del placeholder (da usare con moderazione)inputRequired (booleano, opzionale): Se true, il campo è obbligatorioinputAutocomplete (stringa, opzionale): Valore per l’autocompletamento (riferimento: MDN Web Docs)inputAriaDescribedBy (stringa, opzionale): ID dell’elemento che descrive il campoinputDescription (stringa, opzionale): Descrizione testuale del campoinputAriaInvalid (booleano, opzionale): Indica se il campo contiene un erroreinputHasErrorControl (booleano, opzionale): Se il campo necessita di validazioneerrorDescription (stringa, opzionale): Descrizione dell’erroreinputIconAlert (booleano, opzionale): Se true, mostra l’icona di errore (⚠) a destra dell’input. Per inputType con picker nativo (date, time, datetime-local, month, week) l’icona si posiziona automaticamente a sinistra del controllo nativo del browserinputHasError (booleano, opzionale): Stile di errore per l’inputinputDisabled (booleano, opzionale): Se true, aggiunge disabled all’input e la classe rtds-input-field--disabled al wrapper — label e descrizione appaiono mutedinputReadonly (booleano, opzionale): Se true, aggiunge readonly all’input — nessuno stile aggiuntivo, label invariata, valore inviato nel formpasswordlabel (stringa, obbligatorio): Testo della label (es. “Password”, “Conferma password”)inputId (stringa, obbligatorio): ID univoco del campoinputAutocomplete (stringa, opzionale): Valore autocomplete — usare current-password per login, new-password per registrazione/cambio passwordinputRequired (booleano, opzionale): Se true, aggiunge aria-required="true" e il simbolo * nella labelinputDisabled (booleano, opzionale): Disabilita il campo e il toggle button (via CSS pointer-events: none)inputAriaDescribedBy (stringa, opzionale): ID dell’elemento descrittivo collegato tramite aria-describedbyinputDescription (stringa, opzionale): Testo descrittivo del campoerrorDescription (stringa, opzionale): Messaggio di errore mostrato sotto il campoinputIconPlaceholder (stringa, opzionale): ID dell’icona da mostrare come placeholder a sinistra dell’inputLivello AA — criteri pertinenti:
<label> è sempre associata all’<input> tramite for / id; i messaggi di errore e le descrizioni sono collegati tramite aria-describedbyaria-invalid e annunciati con aria-live="assertive"<label> visibile o nascosta disponibile per screen readeraria-required, aria-describedby e aria-invalid comunicano lo stato del campo<div class="rtds-input-field"> contenente una <label> e il componente @input annidato<label> è associata all’input tramite for="" e rimane disponibile anche quando nascosta visivamente tramite rtds-sr-only<abbr title="obbligatorio">*</abbr> nella label<span aria-live="assertive"> per garantire l’annuncio immediato agli screen reader| Attributo | Valori | Condizione |
|---|---|---|
aria-required |
"true" |
quando inputRequired è true (gestito sul <input> interno) |
aria-describedby |
ID del messaggio di errore e/o descrizione | quando presenti errori o descrizione (gestito sul <input> interno) |
aria-invalid |
"true" |
quando inputAriaInvalid è true (gestito sul <input> interno) |
aria-live |
"assertive" |
sullo span del messaggio di errore |
password| Pattern | Motivazione |
|---|---|
type="button" esplicito sul toggle |
Evita submit accidentale della form |
aria-pressed="false/true" sul toggle |
Espone lo stato nascosto/visibile agli screen reader |
| Etichetta fissa “Mostra password” | Non cambia al toggle — lo stato è comunicato da aria-pressed (scelta intenzionale) |
<span aria-live="assertive"> nascosto |
Annuncia “Password visibile” / “Password nascosta” immediatamente dopo il toggle |
Icona aria-hidden="true" |
Decorativa — il testo .rtds-sr-only è il label accessibile del button |
Nota: L’etichetta del toggle resta “Mostra password” sia prima che dopo il click. Il cambio di stato è comunicato da aria-pressed (letto dagli screen reader) e dall’elemento aria-live (annuncio vocale immediato). Questo è il comportamento atteso e documentato.
hiddenLabel: true), rimane disponibile per screen reader tramite rtds-sr-onlyaria-live="assertive"*) è leggibile tramite l’attributo title="obbligatorio" sull’<abbr><!-- Esempio base -->
<div class="rtds-input-field rtds-gap-1">
<label for="nome" class="rtds-input-field__label">Nome</label>
<input type="text" id="nome" name="nome">
</div>
<!-- Esempio obbligatorio con errore -->
<div class="rtds-input-field rtds-gap-1 rtds-input-field--has-error">
<label for="email" class="rtds-input-field__label">
Email <abbr title="obbligatorio">*</abbr>
</label>
<input type="email" id="email" name="email"
aria-required="true" aria-invalid="true" aria-describedby="email-error">
<span class="rtds-input-field__hint">
<span id="email-error" aria-live="assertive" class="rtds-input-field__error">
Inserire un indirizzo email valido
</span>
</span>
</div>