Design System

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

Use textarea quandoUse textarea when
O usuário precisa inserir texto multilinha: mensagens, descrições, comentários, feedback ou bios. Sempre que a entrada esperada seja mais de uma linha.The user needs to enter multi-line text: messages, descriptions, comments, feedback, or bios. Anywhere the expected input is more than a single line.
Não use textarea quandoDon't use textarea when
A entrada é de uma única linha (use Input), ou você precisa de formatação rich text (use um editor rich text -- não faz parte deste DS).The input is a single line (use Input instead), or you need rich text formatting (use a rich text editor -- not part of this DS).

AnatomiaAnatomy

1 2 3
1 Wrapper (.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>
SizeMin-heightCaso de usoUse case
Small (--sm)80pxEntradas curtas: avaliações, comentários brevesShort inputs: feedback ratings, brief comments
Medium (--md)120pxUso padrão: mensagens, descrições (default)Standard use: messages, descriptions (default)
Large (--lg)160pxConteúdo longo: bios, feedback detalhadoLong-form content: bios, detailed feedback

Contador de caracteresCharacter Counter

0 / 200
<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

Message must be at least 20 characters.
<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

Faça
Defina uma altura inicial razoável (3-4 linhas) que indique o comprimento esperado do conteúdo.Set a reasonable initial height (3-4 rows) that hints at the expected content length.
Não faça
Um textarea de 1 linha parece idêntico a um input -- confuso para os usuários.A 1-row textarea looks identical to an input -- confusing for users.
42 / 200
Faça
Use um contador de caracteres quando houver um limite rígido (tamanho do campo no banco, restrição de API).Use a character counter when there is a hard limit (database field length, API constraint).
0 / 99999
Não faça
Não adicione um contador de caracteres para campos abertos onde o comprimento não é uma preocupação real.Don't add a character counter for open-ended fields where length is not a real concern.

Diretrizes de conteúdoContent guidelines

RegraRuleExemploExample
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--overContador 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.

PropriedadePropertyToken (semantic)Variável CSSCSS variable
backgroundsemantic.surface.default--ds-surface-default
bordersemantic.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 colorsemantic.content.default--ds-content-default
placeholder colorsemantic.content.tertiary--ds-content-tertiary
border-radiussemantic.radius.component--ds-radius-md
focus ringsemantic.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 colorsemantic.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

ClasseClassDescriçãoDescription
ds-textareaElemento wrapper do textareaWrapper element for the textarea
ds-textarea__fieldO elemento nativo <textarea>The native <textarea> element
ds-textarea--smTamanho pequeno (80px min-height)Small size (80px min-height)
ds-textarea--mdTamanho médio (120px min-height, padrão)Medium size (120px min-height, default)
ds-textarea--lgTamanho grande (160px min-height)Large size (160px min-height)
ds-textarea--errorEstado de erro com borda vermelhaError state with red border
ds-textarea--disabledEstado desabilitado (ou use o nativo disabled)Disabled state (or use native disabled)
ds-textarea--readonlyEstado somente leitura (ou use o nativo readonly)Readonly state (or use native readonly)
ds-field__counterElemento contador de caracteresCharacter counter element
ds-field__counter--overAplicado quando contagem de caracteres excede o máximoApplied when character count exceeds max
ds-field__label-rowLinha horizontal com label e asterisco de obrigatórioHorizontal row with label and required asterisk
ds-field__requiredAsterisco * em feedback/error/default (decorativo, aria-hidden)Asterisk * in feedback/error/default (decorative, aria-hidden)
ds-field--no-labelOculta o label row quando Show Label = falseHides the label row when Show Label = false
ds-field--no-helperOculta o helper text quando Show Helper Text = falseHides helper text when Show Helper Text = false

Propriedades FigmaFigma properties

PropriedadePropertyTipoTypePadrãoDefaultDescriçãoDescription
Show LabelBooleantrueExibe ou oculta o label row (incluindo asterisco de obrigatório)Shows or hides the label row (including required asterisk)
LabelText"Rótulo"Texto do label (label/md)Label text (label/md)
RequiredBooleanfalseExibe o asterisco * em feedback/error/default ao lado do labelShows * in feedback/error/default next to the label
Show Helper TextBooleantrueExibe ou oculta o texto auxiliar abaixo do controleShows or hides the helper text below the control
Helper TextText"Texto auxiliar"Anotação em caption/sm (content/secondary)Caption/sm annotation (content/secondary)

Interação por tecladoKeyboard interaction

TeclaKeyAçãoAction
TabMove o foco para dentro / fora do textareaMoves focus into / out of the textarea
EnterInsere uma nova linha (NÃO envia o formulário)Inserts a new line (does NOT submit the form)
Qualquer caractereAny characterDigita 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 criterionRequisitoRequirementStatus
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.
Resumo de atributos ARIAARIA attributes summary
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 e label invisívelRequired and invisible label
Quando 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.

RelacionadosRelated