TIS Design System

Form Field

Wrapper composite que junta label, controle (Input/Select/Textarea), required indicator, helper text e error message. É onde a acessibilidade de form se materializa: associação correta de label↔controle, aria-describedby pra helper, aria-invalid em estado de erro.Composite wrapper that pairs label, control (Input/Select/Textarea), required indicator, helper text, and error message. This is where form accessibility lives: correct label↔control association, aria-describedby for helpers, aria-invalid on error.

Quando usarWhen to use

Use Form Field quandoUse Form Field when
Qualquer controle de formulário precisar de label visível, helper text ou validação. Sempre que houver Input, Select ou Textarea com contexto adicional, eles devem estar dentro de um Form Field — é o que conecta os pedaços de forma acessível.Any form control needs a visible label, helper text, or validation. Whenever you have an Input, Select, or Textarea with additional context, they should live inside a Form Field — it connects the pieces accessibly.
Não use Form Field quandoDon't use Form Field when
O controle não precisa de label visível (ex: search input no header com ícone, com aria-label direto no controle). Mesmo assim, considere usar Form Field com --no-label para manter consistência de espaçamento.The control doesn't need a visible label (e.g., search input in header with icon, using aria-label directly). Even so, consider Form Field with --no-label to keep spacing consistent.
CSS-only (ADR-017)
Form Field não tem equivalente Figma dedicado. Ele existe para compor markup HTML/ARIA; Input, Select, Textarea, Checkbox, Radio e Toggle já carregam seus elementos de label/helper nas variants Figma.Form Field has no dedicated Figma equivalent. It exists to compose HTML/ARIA markup; Input, Select, Textarea, Checkbox, Radio, and Toggle already include label/helper elements in their Figma variants.

AnatomiaAnatomy

1
3
We'll never share your email. 4 Please enter a valid email. 5
1 Label (.ds-field__label) — texto descritivo, com for= apontando pro id do controle.
2 Required indicator (.ds-field__required) — asterisco visual, aria-hidden="true" (a obrigatoriedade vem do aria-required no controle).
3 Controle — Input/Select/Textarea/Checkbox group, com id matching o label e aria-describedby apontando pro helper.
4 Helper text (.ds-field__helper) — orientação ou contexto adicional, com id referenciado pelo aria-describedby do controle.
5 Error message (.ds-field__error) — ícone + mensagem de validação, aparece apenas em .ds-field--error com role="alert".
1 Label (.ds-field__label) — descriptive text with for= pointing to the control's id.
2 Required indicator (.ds-field__required) — visual asterisk, aria-hidden="true" (required state comes from aria-required on the control).
3 Control — Input/Select/Textarea/Checkbox group, with matching id and aria-describedby pointing to the helper.
4 Helper text (.ds-field__helper) — guidance or additional context, with id referenced by control's aria-describedby.
5 Error message (.ds-field__error) — icon + validation message, shown only in .ds-field--error with role="alert".

Encapsulando controlesWrapping form controls

Form Field é agnóstico ao tipo de controle. Funciona com Input, Textarea e Select via label[for]. Para grupos (Checkbox/Radio), use <fieldset> + <legend> em vez de label/for individual — a semântica de grupo é diferente da semântica de controle único.Form Field is control-agnostic. Works with Input, Textarea, and Select via label[for]. For groups (Checkbox/Radio), use <fieldset> + <legend> instead of individual label/for — group semantics differ from single-control semantics.

As shown on your ID.
Up to 500 characters.
Used for shipping calculations.
Notification preferences
Choose how we contact you.
Plan
You can change this anytime.

Nota: para grupos, aria-describedby vai no container do grupo; <legend> substitui <label>. O wrapper <fieldset class="ds-field"> herda o gap vertical igual ao Input.Note: for groups, aria-describedby goes on the group container; <legend> replaces <label>. The <fieldset class="ds-field"> wrapper inherits the same vertical gap as Input.

Error stateError state

Adicione .ds-field--error no wrapper, aria-invalid="true" + aria-describedby no controle apontando para o id do error. role="alert" no error garante anúncio imediato para screen readers.Add .ds-field--error on the wrapper, aria-invalid="true" + aria-describedby on the control pointing to the error's id. role="alert" on the error ensures immediate screen reader announcement.

Please enter a valid email address.
<div class="ds-field ds-field--error">
  <div class="ds-field__label-row">
    <label class="ds-field__label" for="email">Email address</label>
    <span class="ds-field__required" aria-hidden="true">*</span>
  </div>
  <div class="ds-input ds-input--error">
    <input type="email" id="email" class="ds-input__field"
           value="not-an-email"
           aria-required="true"
           aria-invalid="true"
           aria-describedby="email-error">
  </div>
  <span class="ds-field__error" id="email-error" role="alert">
    Please enter a valid email address.
  </span>
</div>

Boas práticasBest practices

FaçaDo
Use label[for], id e aria-describedby para conectar visual e semântica.Use label[for], id, and aria-describedby to connect visuals and semantics.
Não façaDon't
Não replique Form Field como componente Figma separado; isso duplicaria elementos já presentes nas variants dos controles.Do not replicate Form Field as a separate Figma component; that would duplicate elements already present in control variants.

Checklist de acessibilidadeAccessibility checklist

Mapeamento de tokensToken mapping

PropriedadePropertyToken (Component)Variável CSSCSS variable
root gapcomponent.form-field.gap.default--ds-form-field-gap-default
label-row gapcomponent.form-field.label-row.gap.default--ds-form-field-label-row-gap-default
label colorcomponent.form-field.label.color.{default,disabled,readonly}--ds-form-field-label-color-*
required colorcomponent.form-field.required.color.default--ds-form-field-required-color-default
helper colorcomponent.form-field.helper.color.default--ds-form-field-helper-color-default
error colorcomponent.form-field.error.color.default--ds-form-field-error-color-default
error gapcomponent.form-field.error.gap.default--ds-form-field-error-gap-default
error iconcomponent.form-field.error.icon.{color,size,stroke-width}.default + component.form-field.error.icon-frame.padding-x.default--ds-form-field-error-icon-*-default, --ds-form-field-error-icon-frame-padding-x-default
label typographycomponent.form-field.label.{font-size,line-height,font-weight}.default--ds-form-field-label-*-default
helper/error typographycomponent.form-field.{helper,error}.{font-size,line-height,font-weight}.default--ds-form-field-helper-*-default / --ds-form-field-error-*-default

Esses tokens existem como contrato CSS-only do Form Field. Eles aliasam Semantic quando o valor já é uma decisão reutilizável e não criam um componente visual Form Field no Figma, conforme ADR-017.These tokens exist as the CSS-only Form Field contract. They alias Semantic when the value is already reusable and do not create a visual Form Field component in Figma, per ADR-017.

Classes CSSCSS classes

ClasseClassUsoUsage
ds-fieldWrapper. Stack vertical com gap consistente.Wrapper. Vertical stack with consistent gap.
ds-field__label-rowLinha do label + required (horizontal).Label + required row (horizontal).
ds-field__labelTexto do label (14px medium).Label text (14px medium).
ds-field__requiredAsterisco visual (decorativo, aria-hidden).Visual asterisk (decorative, aria-hidden).
ds-field__helperHelper text (12px secundário).Helper text (12px secondary).
ds-field__errorLinha de erro com ícone automático e mensagem. Visível apenas em --error.Error row with automatic icon and message. Visible only with --error.
ds-field--errorModificador: estado de erro. Mostra error message e aplica o contrato de erro ao controle associado.Modifier: error state. Shows error message and applies the error contract to the associated control.
ds-field--no-labelModificador: esconde label-row. Usar com aria-label no controle.Modifier: hides label-row. Pair with aria-label on control.
ds-field--no-helperModificador: esconde helper.Modifier: hides helper.

RelacionadosRelated