Field
.field e un câmp — etichetă, control, ajutor, eroare. .fieldset e colecția. Controlul în sine e documentat la componenta lui; aici e ce-l ține în pagină. Structura urmează documentația Field din shadcn.
Input ·
.input e controlul: cutia în care scrii. Nu știe de etichetă, ajutor sau eroare.Field ·
.field e tot ce e în afara bordurii: etichetă, ajutor, eroare, orientare. Agnostic la control.Input group ·
.input-group e tot ce e în interiorul bordurii: iconiță, text, buton, scurtătură — sau eticheta însăși. Nu e o pagină, e același control cu ceva în el.Se cuibăresc, nu concurează:
.field > .input-group > .input. Împărțirea e a lui shadcn — Input e controlul, Field „combines labels, controls, and help text”, InputGroup „adds addons, buttons, and helper content to inputs”.
Cele patru straturi
.input CONTROLUL — cutia în care scrii .input-group ÎN interiorul bordurii: iconiță, text, buton, scurtătură .field CÂMPUL — ÎN AFARA bordurii: etichetă, ajutor, eroare .fieldset GRUPUL cu titlu · .field-row grupul pe orizontală
| Întrebarea | Răspunsul |
|---|---|
| Unde stă eticheta? | În .field, ca .field-label. Niciodată ca addon — addon-ul e o bară, nu o etichetă. |
| Unde stă eroarea? | Mesajul în .field-help.error; conturul pe control, prin .error. |
| Unde pun iconița? | În .input-group. În .field ar fi lângă câmp, nu în el. |
Îmi trebuie .field? | Doar dacă ai etichetă, ajutor sau eroare. Căutarea din topbar n-are niciuna. |
Markup canonic · components/field.json
Părțile
| Bono | Ce e | Specificație | shadcn |
|---|---|---|---|
.field | UN câmp: etichetă + control + ajutor | coloană · gap 4 | Field |
.field-label | eticheta câmpului, DEASUPRA lui | 12/16 · 500 · 0.04em · fog sentence case · pad-left 16 | FieldLabel |
.field-help | textul de sub control | 12/16 · 400 · fog · pad-left 16 | FieldDescription |
.field-help.error | același loc, mesaj de eroare | --c-error-text | FieldError |
.field-content | coloana de text a unui câmp orizontal | coloană · gap 2 · min-width 0 anulează pad-left pe label și help | FieldContent |
.field-title | titlul unui câmp care nu e <label> | alias al lui .label 15/22 · 400 · ink | FieldTitle |
.fieldset | GRUPUL de câmpuri, cu titlu | coloană · gap 18 fără contur, fără padding | FieldSet |
.fieldset-legend | titlul grupului | 13/18 · 600 · ink · mb 2 | FieldLegend |
.fieldset-help | descrierea grupului | 13/18 · fog · ancorat sub legend | FieldDescription |
.field-row | câmpuri înrudite pe același rând | grid egal · gap 12 .cols-2 · .cols-3 · .grow-last | FieldGroup orizontal |
.separator.soft | linia dintre două câmpuri din grup | 1px --c-rule-soft | FieldSeparator |
.label | eticheta unui CONTROL, lângă el | 15/22 · 400 · ink | Label |
Trei dintre ele se numeau „label" sau „field" în conversație — de acolo a apărut al șaselea, în aplicație. .field-label e sentence case: „Denumire firmă", nu „DENUMIRE FIRMĂ". Uppercase apare doar pe eticheta din interiorul bordurii (.input-group cu block-start).
Spațiere
Banda roz e distanța, la scară 1:1 — nu o notează, o arată.
.field — gap 4px
.fieldset — gap 18px
.field-row — gap 12px
.field.horizontal — gap 16px
.input-group — gap 8px, în bordură
Pe orizontală câmpurile stau mai aproape decât pe verticală — 12 față de 18. Cu același gap, un rând de două câmpuri s-ar citi ca două grupuri separate. Cei 16px de padding-left pe .field-label și .field-help aliniază textul cu interiorul inputului; într-un .field-content nu există input dedesubt, deci acolo sunt 0.
Orientare
Vertical e implicit. Orizontal e pentru controalele care își spun starea singure — switch, checkbox. Orientarea schimbă axa, nu vocabularul: eticheta trecută lângă control nu mai e .field-label, e .label.
.field.field.horizontal + .field-content.field.responsive — orizontal peste 1024px, vertical dedesubt (îngustează fereastra).field.horizontal, .field.responsive, .field-content și .field-title înlocuiesc rândurile scrise cu style inline — lista de setări din Switch avea același layout copiat de trei ori. De validat pe un ecran de setări real.Ajutor, eroare, confirmare
Un singur slot sub control, trei sensuri. Un câmp nu are două locuri unde să scrie ceva.
Label-ul nu se înroșește: bordura, tintul și mesajul spun deja același lucru. Confirmarea se folosește doar când aduce informație, nu ca bifă pe fiecare câmp completat.
Care etichetă, la care control
Ce se schimbă de la un control la altul e unde stă eticheta — și de acolo, cum se numește.
| Controlul | Eticheta | Clasa |
|---|---|---|
| input, select, textarea | deasupra, în afara controlului | .field-label într-un .field |
| un singur checkbox sau switch | lângă control, e propoziția lui | .check-label într-un .check-item |
| grup de radio sau checkbox | deasupra grupului, dar nu e <label> | .field-title + .radio-group |
.field + .field-label.check-item, fără .field-label.field + .field-title + .radio-groupTitlul grupului nu poate fi un <label>: un for="" ar alege una dintre opțiuni, deci titlul ar deveni clicabil pe prima. Opțiunile stau în .radio-group (gap 10px), nu direct în .field (gap 4px) — aia e distanța dintre etichetă și controlul ei, nu dintre două opțiuni.
Grupul · .fieldset
Un <fieldset> real cu <legend> real — cititorul de ecran anunță legenda la fiecare câmp din grup. Fără contur și fără padding: conturul îl dă cardul din jur.
Maxim un nivel de imbricare. Un formular care cere al treilea nivel are nevoie de un pas în plus, nu de grupuri mai adânci — la fel peste ~8 câmpuri într-un grup.
Separator în grup
Când două câmpuri din același grup nu vorbesc despre același lucru: <hr class="separator soft">, direct copil de .fieldset. Gap-ul de 18px cade de ambele părți, deci linia stă centrată fără margini proprii. .separator tare separă secțiuni, nu câmpuri.
Câmpuri înrudite pe un rând
Testul: dacă utilizatorul le citește ca o informație — perioada, data, suma — e un .field-row. Dacă nu, sunt două câmpuri într-un .fieldset.
.input-group. Numele a trecut la stratul de dedesubt — Input group, secțiune pe pagina Input — fiindcă asta înseamnă InputGroup în shadcn, iar rândul de câmpuri e FieldGroup. Fără alias: pe un nume reutilizat, un alias ar face chiar greșeala pe care redenumirea o repară.De revizuit
.fieldset merită contur propriu când e imbricat; cum arată un legend pe două rânduri; dacă 18px ține peste ~8 câmpuri; și dacă un câmp orizontal cu eroare ține mesajul în .field-content sau pe tot rândul.