Textarea
Textareas permitem que usuários insiram texto multilinha. Usa um padrão de wrapper similar ao componente Input.Textareas let users enter multi-line text. Uses a wrapper pattern similar to the Input component.
Quando usarWhen to use
AnatomiaAnatomy
.ds-textarea) -- mesmo padrão de borda/radius do Input.2 Campo (
.ds-textarea__field) -- o elemento nativo <textarea>.3 Alça de redimensionamento -- nativa do navegador, apenas vertical por padrão.
Contador de caracteres (opcional,
.ds-field__counter) -- disponível via wrapper Form Field.1 Wrapper (.ds-textarea) -- same border/radius pattern as Input.2 Field (
.ds-textarea__field) -- the native <textarea> element.3 Resize handle -- browser-native, vertical only by default.
Character counter (optional,
.ds-field__counter) -- available via Form Field wrapper.
PadrãoDefault
<div class="ds-textarea">
<textarea class="ds-textarea__field" placeholder="Enter your message..."></textarea>
</div>
TamanhosSizes
<div class="ds-textarea ds-textarea--sm">
<textarea class="ds-textarea__field" placeholder="Small"></textarea>
</div>
<div class="ds-textarea ds-textarea--md">
<textarea class="ds-textarea__field" placeholder="Medium"></textarea>
</div>
<div class="ds-textarea ds-textarea--lg">
<textarea class="ds-textarea__field" placeholder="Large"></textarea>
</div>
| Size | Min-height | Caso de usoUse case |
|---|---|---|
Small (--sm) | 80px | Entradas curtas: avaliações, comentários brevesShort inputs: feedback ratings, brief comments |
Medium (--md) | 120px | Uso padrão: mensagens, descrições (default)Standard use: messages, descriptions (default) |
Large (--lg) | 160px | Conteúdo longo: bios, feedback detalhadoLong-form content: bios, detailed feedback |
Contador de caracteresCharacter Counter
<div class="ds-field">
<label class="ds-field__label" for="bio">Bio</label>
<div class="ds-textarea">
<textarea class="ds-textarea__field" id="bio"
data-maxlength="200" data-counter="bio-counter"></textarea>
</div>
<span class="ds-field__counter" id="bio-counter"
aria-live="polite">0 / 200</span>
</div>
EstadosStates
Error
<div class="ds-field ds-field--error">
<label class="ds-field__label" for="msg">Message</label>
<div class="ds-textarea">
<textarea class="ds-textarea__field" id="msg"
aria-invalid="true" aria-describedby="msg-error"></textarea>
</div>
<span class="ds-field__error" id="msg-error">Message must be at least 20 characters.</span>
</div>
Disabled
<div class="ds-textarea">
<textarea class="ds-textarea__field" disabled>Disabled textarea</textarea>
</div>
Readonly
<div class="ds-textarea">
<textarea class="ds-textarea__field" readonly>Read-only content</textarea>
</div>
Boas práticasBest practices
Diretrizes de conteúdoContent guidelines
| RegraRule | ExemploExample |
|---|---|
| Labels seguem as mesmas regras do InputLabels follow the same rules as Input | "Message", "Description", "Bio" -- not "Enter your message here" |
| Placeholders podem ser um pouco mais longos (campo mais largo)Placeholders can be slightly longer (wider field) | "Tell us about your experience..." -- not just "Type here" |
| Mensagens de erro descrevem o que deu errado e como corrigirError messages describe what went wrong and how to fix | "Message must be at least 20 characters." -- not "Error" |
| Formato do contador: atual / máximoCharacter counter format: current / max | "42 / 200" -- not "42 characters" or "158 remaining" |
Contador acima do limite usa ds-field__counter--overOver-limit counter uses ds-field__counter--over | Contador fica vermelho quando atual > máximoCounter turns red when current > max |
Mapeamento de tokensToken mapping
Mesmos tokens do Input, mais tokens específicos de min-height e contador do textarea.Same tokens as Input, plus textarea-specific min-height and counter tokens.
| PropriedadeProperty | Token (semantic) | Variável CSSCSS variable |
|---|---|---|
| background | semantic.surface.default | --ds-surface-default |
| border | semantic.border.default | --ds-border-default |
| border (hover) | semantic.border.control-hover | --ds-border-control-hover |
| border (focus) | semantic.primary.background.default | --ds-primary-background-default |
| border (error) | semantic.feedback.error.bg-default | --ds-feedback-error-background-default |
| text color | semantic.content.default | --ds-content-default |
| placeholder color | semantic.content.tertiary | --ds-content-tertiary |
| border-radius | semantic.radius.component | --ds-radius-md |
| focus ring | semantic.focus.ring.* | --ds-focus-ring-width, --ds-focus-ring-offset, --ds-focus-ring-color |
| padding-x (sm/md/lg) | semantic.space.control.padding-x.* | --ds-space-md/md/lg |
| padding-y (sm) | semantic.space.control.padding-y.sm | --ds-space-sm (8px) |
| padding-y (md) | semantic.space.control.padding-y.md | --ds-space-control-padding-10 (10px, was 12px) |
| padding-y (lg) | semantic.space.control.padding-y.lg | --ds-space-md (12px, was 16px) |
| font-size (sm) | semantic.typography.control.font-size.sm | --ds-control-font-size-sm |
| font-size (md) | semantic.typography.control.font-size.md | --ds-control-font-size-md |
| font-size (lg) | semantic.typography.control.font-size.lg | --ds-control-font-size-lg |
| min-height (sm) | -- | 80px |
| min-height (md) | -- | 120px |
| min-height (lg) | -- | 160px |
| counter color | semantic.content.secondary | --ds-content-secondary |
| counter color (over) | semantic.feedback.error.content-default | --ds-feedback-error-content-default |
Nota: Height e line-height permanecem independentes do sistema compartilhado de tokens de controle. Textarea é multilinha, então usa min-height por tamanho em vez dos heights fixos semantic.size.control.* usados por controles de linha única (Button, Input, Select).Note: Height and line-height remain independent of the shared control token system. Textarea is multi-line, so it uses min-height per size rather than the fixed semantic.size.control.* heights used by single-line controls (Button, Input, Select).
Classes CSSCSS classes
| ClasseClass | DescriçãoDescription |
|---|---|
ds-textarea | Elemento wrapper do textareaWrapper element for the textarea |
ds-textarea__field | O elemento nativo <textarea>The native <textarea> element |
ds-textarea--sm | Tamanho pequeno (80px min-height)Small size (80px min-height) |
ds-textarea--md | Tamanho médio (120px min-height, padrão)Medium size (120px min-height, default) |
ds-textarea--lg | Tamanho grande (160px min-height)Large size (160px min-height) |
ds-textarea--error | Estado de erro com borda vermelhaError state with red border |
ds-textarea--disabled | Estado desabilitado (ou use o nativo disabled)Disabled state (or use native disabled) |
ds-textarea--readonly | Estado somente leitura (ou use o nativo readonly)Readonly state (or use native readonly) |
ds-field__counter | Elemento contador de caracteresCharacter counter element |
ds-field__counter--over | Aplicado quando contagem de caracteres excede o máximoApplied when character count exceeds max |
ds-field__label-row | Linha horizontal com label e asterisco de obrigatórioHorizontal row with label and required asterisk |
ds-field__required | Asterisco * em feedback/error/default (decorativo, aria-hidden)Asterisk * in feedback/error/default (decorative, aria-hidden) |
ds-field--no-label | Oculta o label row quando Show Label = falseHides the label row when Show Label = false |
ds-field--no-helper | Oculta o helper text quando Show Helper Text = falseHides helper text when Show Helper Text = false |
Propriedades FigmaFigma properties
| PropriedadeProperty | TipoType | PadrãoDefault | DescriçãoDescription |
|---|---|---|---|
Show Label | Boolean | true | Exibe ou oculta o label row (incluindo asterisco de obrigatório)Shows or hides the label row (including required asterisk) |
Label | Text | "Rótulo" | Texto do label (label/md)Label text (label/md) |
Required | Boolean | false | Exibe o asterisco * em feedback/error/default ao lado do labelShows * in feedback/error/default next to the label |
Show Helper Text | Boolean | true | Exibe ou oculta o texto auxiliar abaixo do controleShows or hides the helper text below the control |
Helper Text | Text | "Texto auxiliar" | Anotação em caption/sm (content/secondary)Caption/sm annotation (content/secondary) |
Interação por tecladoKeyboard interaction
| TeclaKey | AçãoAction |
|---|---|
Tab | Move o foco para dentro / fora do textareaMoves focus into / out of the textarea |
Enter | Insere uma nova linha (NÃO envia o formulário)Inserts a new line (does NOT submit the form) |
| Qualquer caractereAny character | Digita no campoTypes into the field |
Diferente de inputs de linha única, pressionar Enter dentro de um textarea cria uma nova linha em vez de enviar o formulário. Este é o comportamento nativo do navegador.Unlike single-line inputs, pressing Enter inside a textarea creates a new line instead of submitting the form. This is native browser behavior.
AccessibilityAccessibility
| Critério WCAGWCAG criterion | RequisitoRequirement | Status |
|---|---|---|
| 1.3.1 Info and Relationships (A) | Every textarea must have a visible <label> with matching for/id. | ✓ |
| 1.3.5 Identify Input Purpose (AA) | Use autocomplete attributes where applicable (e.g. autocomplete="street-address"). | ✓ |
| 1.4.3 Contrast (AA) | Text and placeholder meet 4.5:1 and 3:1 contrast respectively. | ✓ |
| 2.4.11 Focus Appearance (AA) | Focus ring 2px + 2px gap, contrast ≥ 3:1 against adjacent colors. | ✓ |
| 3.3.1 Error Identification (A) | Error state uses aria-invalid="true" + aria-describedby linking to the error message. | ✓ |
| 3.3.2 Labels or Instructions (A) | Placeholder is supplemental, never a replacement for the label. | ✓ |
| 4.1.3 Status Messages (AA) | Character counter uses aria-live="polite" so screen readers announce updates. | ✓ |
aria-invalid="true" -- definido quando o campo tem erro de validação.aria-describedby -- referencia o ID do elemento de mensagem de erro ou texto auxiliar.aria-live="polite" -- no contador de caracteres para atualizações dinâmicas de leitores de tela.Se
maxlength estiver definido no elemento nativo, navegadores impõem o limite -- sem necessidade de validação JS.aria-invalid="true" -- set when the field has a validation error.aria-describedby -- references the error message or helper text element ID.aria-live="polite" -- on the character counter for dynamic screen reader updates.If
maxlength is set on the native element, browsers enforce the limit -- no JS validation needed.
Required = true, adicione aria-required="true" no <textarea> — o asterisco visual (.ds-field__required) é decorativo (aria-hidden="true"). Quando Show Label = false, use aria-label no <textarea>. O Helper Text deve ser vinculado via aria-describedby.When Required = true, add aria-required="true" to the <textarea> — the visual asterisk (.ds-field__required) is decorative (aria-hidden="true"). When Show Label = false, use aria-label on the <textarea>. Helper Text should be linked via aria-describedby.