TIS Design System

Select

Menus Select permitem que usuários escolham uma opção de uma lista dropdown. Usa um padrão de wrapper com <select> nativo e um indicador de seta customizado.Select menus allow users to choose one option from a dropdown list. Uses a wrapper pattern with native <select> and a custom arrow indicator.

Quando usarWhen to use

Use Select quandoUse Select when
O usuário deve escolher exatamente uma opção de uma lista predefinida de 5 ou mais itens.The user must choose exactly one option from a predefined list of 5 or more items.
Não use Select quandoDon't use Select when
Menos de 5 opções — use Radio. Múltiplas seleções permitidas — use grupo de Checkbox. Usuário precisa buscar ou filtrar — use Combobox.Fewer than 5 options — use Radio instead. Multiple selections allowed — use Checkbox group. User needs to search or filter — use Combobox.

AnatomiaAnatomy

7
1 2 3 4
Please select a country. 5
Choose one country from the list. 6
1 Wrapper (.ds-select) — container com borda, radius.
2 Ícone (opcional, .ds-select__icon) — ícone à esquerda, decorativo.
3 Campo (.ds-select__field) — elemento nativo <select>.
4 Seta (.ds-select__arrow) — chevron customizado, pointer-events: none.
5 Mensagem de erro (.ds-field__error) — externa, via Form Field.
6 Texto auxiliar (.ds-field__helper) — externo, via Form Field.
7 Label (.ds-field__label) — externo, via Form Field.
1 Wrapper (.ds-select) — container with border, radius.
2 Icon (optional, .ds-select__icon) — leading icon, decorative.
3 Field (.ds-select__field) — native <select> element.
4 Arrow (.ds-select__arrow) — custom chevron, pointer-events: none.
5 Error message (.ds-field__error) — external, via Form Field.
6 Helper text (.ds-field__helper) — external, via Form Field.
7 Label (.ds-field__label) — external, via Form Field.

PadrãoDefault

Helper text
<div class="ds-field">
  <div class="ds-field__label-row">
    <label class="ds-field__label" for="select-default">Label</label>
  </div>
  <div class="ds-select">
    <select class="ds-select__field" id="select-default"
            aria-describedby="select-default-helper">
      <option value="" disabled selected>Choose an option</option>
      <option value="1">Option One</option>
      <option value="2">Option Two</option>
      <option value="3">Option Three</option>
    </select>
    <span class="ds-select__arrow"></span>
  </div>
  <span class="ds-field__helper" id="select-default-helper">Helper text</span>
</div>

TamanhosSizes

<div class="ds-select ds-select--sm">
  <select class="ds-select__field">...</select>
  <span class="ds-select__arrow"></span>
</div>

<div class="ds-select ds-select--md">
  <select class="ds-select__field">...</select>
  <span class="ds-select__arrow"></span>
</div>

<div class="ds-select ds-select--lg">
  <select class="ds-select__field">...</select>
  <span class="ds-select__arrow"></span>
</div>
SizeHeightFontPaddingTouch target
Small (--sm)32px (component.select.height.sm)component.select.text.font-size.smcomponent.select.padding-x.sm / component.field.padding-y.sm32px — meets WCAG 2.5.8 min (24px)
Medium (--md)40px (component.select.height.md)component.select.text.font-size.mdcomponent.select.padding-x.md / component.field.padding-y.md40px
Large (--lg)48px (component.select.height.lg)component.select.text.font-size.lgcomponent.select.padding-x.lg / component.field.padding-y.lg48px — meets AAA 44px target

Com íconeWith icon

<div class="ds-select">
  <i data-lucide="languages" class="ds-select__icon ds-icon"></i>
  <select class="ds-select__field">
    <option>English</option>
    <option>Portuguese</option>
    <option>Spanish</option>
  </select>
  <span class="ds-select__arrow"></span>
</div>

EstadosStates

No Figma, State representa apenas estados visuais exclusivos: Default, Hover, Focus e Disabled. Filled, Error e Read-only são propriedades separadas; Error combina com Default/Hover/Focus, e Read-only combina com Default/Focus.In Figma, State only represents exclusive visual states: Default, Hover, Focus, and Disabled. Filled, Error, and Read-only are separate properties; Error combines with Default/Hover/Focus, and Read-only combines with Default/Focus.

Error

Please select a country. Choose one country from the list.
<div class="ds-field ds-field--error">
  <label class="ds-field__label" for="country">Country<span class="ds-field__required">*</span></label>
  <div class="ds-select ds-select--error">
    <select class="ds-select__field" id="country" aria-invalid="true" aria-describedby="country-error">
      <option value="" disabled selected>Select a country</option>
      <option>Brazil</option>
    </select>
    <span class="ds-select__arrow"></span>
  </div>
  <span class="ds-field__error" id="country-error">Please select a country.</span>
  <span class="ds-field__helper">Choose one country from the list.</span>
</div>

Disabled

<div class="ds-select">
  <select class="ds-select__field" disabled>
    <option>Disabled option</option>
  </select>
  <span class="ds-select__arrow"></span>
</div>

Readonly

<!-- Native select has no readonly; use disabled + ds-select--readonly for styling -->
<div class="ds-select ds-select--readonly">
  <select class="ds-select__field" disabled>
    <option>Read-only value</option>
  </select>
  <span class="ds-select__arrow"></span>
</div>
Figma propertyValue / CSS triggerVisual changeToken
StateDefaultNeutral bordercomponent.field.border-color.default
StateHover / :hoverDarker bordercomponent.field.border-color.hover
StateFocus / :focus-visible2px outline ring, component radiuscomponent.field.border-color.focus, component.focus-ring.*, component.select.focus-ring.radius.default
StateDisabled / [disabled]Muted bg + content, no pointer eventscomponent.field.bg.disabled, component.field.value.color.disabled, component.field.placeholder.color.disabled
ErrorTrue / .ds-select--error or .ds-field--error .ds-selectRed border and error focus ringcomponent.field.border-color.error, component.focus-ring.color.error
Error + StateTrue + Hover / .ds-select--error:hoverDarker red bordercomponent.field.border-color.error-hover
Read-onlyTrue / .ds-select--readonly + [disabled]Readonly bg and content treatment; native select has no real readonly focuscomponent.field.bg.readonly, component.field.value.color.readonly

Boas práticasBest practices

Faça
Inclua uma opção placeholder desabilitada: <option value="" disabled selected>Choose a country</option>.Include a disabled placeholder option: <option value="" disabled selected>Choose a country</option>.
Não faça
Pré-selecionar uma opção real a menos que seja um padrão genuíno.Pre-select a real option unless it's a genuine default.
Faça
Ordene as opções logicamente -- alfabeticamente para países, por frequência para escolhas comuns.Order options logically -- alphabetical for countries, by frequency for common choices.
Não faça
Não use select para escolhas booleanas -- use Toggle ou Checkbox.Don't use a select for boolean choices -- use Toggle or Checkbox.

Diretrizes de conteúdoContent guidelines

RegraRuleExemploExample
Placeholder: "Choose a..." or "Select a..." in sentence case"Choose a country" -- not "CHOOSE A COUNTRY" or "Country"
Option text should be concise and consistent"Brazil", "United States" -- not "The Federative Republic of Brazil"
Don't mix option typesAll countries, or all languages -- not countries mixed with regions
Use sentence case for options"Credit card" -- not "Credit Card" or "CREDIT CARD"
Always pair with a <label><label for="country">Country</label>

Mapeamento de tokensToken mapping

Select consome tokens Component no CSS e nos bindings do Figma. Esses tokens documentam o contrato público do componente e aliasam Semantic quando o valor é reutilizável.Select consumes Component tokens in CSS and Figma bindings. These tokens document the component's public contract and alias Semantic when the value is reusable.

PropriedadePropertyToken ComponentVariável CSSCSS variable
bgcomponent.field.bg.{default|focus|filled|error|disabled|readonly}--ds-field-bg-*
border colorcomponent.field.border-color.{default|hover|focus|filled|error|disabled|readonly}--ds-field-border-color-*
border widthcomponent.field.border-width--ds-field-border-width
content colorcomponent.field.value.color.{default|disabled|readonly}--ds-field-value-color-*
placeholder colorcomponent.field.placeholder.color.{default|disabled}--ds-field-placeholder-color-*
chevroncomponent.field.icon.{color|size|stroke-width}.* + component.field.icon-frame.padding-x.default--ds-field-icon-*, --ds-field-icon-frame-padding-x-default
heightcomponent.select.height.{sm|md|lg}--ds-select-height-*
gapcomponent.field.gap.{sm|md|lg}--ds-field-gap-*
paddingcomponent.select.padding-x.* / component.field.padding-y.*--ds-select-padding-x-* / --ds-field-padding-y-*
radiuscomponent.field.radius--ds-field-radius
focus ringcomponent.focus-ring.* + component.select.focus-ring.radius.default--ds-focus-ring-* + --ds-select-focus-ring-radius-default
typographycomponent.field.text.* + component.form-field.{label|helper|required}.*--ds-field-text-*, --ds-form-field-*

Classes CSSCSS classes

ClasseClassDescriçãoDescription
ds-selectElemento wrapper do selectWrapper element for the select
ds-select__fieldO elemento nativo <select>The native <select> element
ds-select__arrowIndicador de seta dropdown customizadoCustom dropdown arrow indicator
ds-select__iconÍcone à esquerda dentro do wrapperLeading icon inside the wrapper
ds-select--smTamanho pequeno (altura 32px)Small size (32px height)
ds-select--mdTamanho médio (altura 40px, padrão)Medium size (40px height, default)
ds-select--lgTamanho grande (altura 48px)Large size (48px height)
ds-select--errorEstado de erro com borda vermelhaError state with red border
ds-select--disabledEstado desabilitado (ou use o nativo disabled)Disabled state (or use native disabled)
ds-select--readonlyEstado visual somente leitura (combine com o nativo disabled)Readonly visual state (combine with native disabled)
ds-field__errorLinha de erro com ícone automático e mensagem (exibida quando ds-field--error está definido)Error row with automatic icon and message (shown when ds-field--error is set)
ds-field__label-rowLinha horizontal com label e asterisco de obrigatórioHorizontal row with label and required asterisk
ds-field__requiredAsterisco * em feedback/error/content/default (decorativo, aria-hidden)Asterisk * in feedback/error/content/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/content/default ao lado do labelShows * in feedback/error/content/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 o selectMoves focus to the select
Space / EnterAbre o dropdown (nativo do navegador)Opens the dropdown (browser-native)
Arrow Up / Arrow DownNavega entre as opçõesNavigates options
EscapeFecha o dropdownCloses dropdown
Any letterPula para a primeira opção que começa com aquela letraJumps to first option starting with that letter

Todas as interações de teclado são tratadas nativamente pelo elemento <select>. Nenhum JavaScript customizado é necessário. Selects desabilitados são removidos da ordem de tabulação automaticamente.All keyboard interactions are handled natively by the <select> element. No custom JavaScript is required. Disabled selects are removed from tab order automatically.

AccessibilityAccessibility

Critério WCAGWCAG criterionRequisitoRequirementStatus
2.4.11 Focus Appearance (AA)Focus ring 2px + 2px gap, contrast >= 3:1 against adjacent colors
2.5.8 Target Size min (AA)Smallest size (32px) exceeds 24px minimum
2.5.5 Target Size (AAA)Large (48px) meets 44px touch target
1.4.3 Contrast (AA)Text and arrow contrast >= 4.5:1 against background. Disabled exempt.
4.1.2 Name, Role, Value (A)Use native <select> element. Associate with <label> via for/id.
1.3.1 Info and Relationships (A)Error states use aria-invalid="true" and aria-describedby.
1.4.1 Use of Color (A)Error state has visible red border + text message, not just color.
Notas de implementaçãoImplementation notes
A seta customizada (.ds-select__arrow) usa pointer-events: none -- é puramente decorativa e não interfere com interação de clique ou teclado.

O <select> nativo não possui atributo readonly. O DS usa disabled combinado com a classe ds-select--readonly para diferenciação visual. Diferente de disabled, readonly deve comunicar visualmente que o valor está definido mas não é editável.
The custom arrow (.ds-select__arrow) uses pointer-events: none -- it is purely decorative and does not interfere with click or keyboard interaction.

Native <select> has no readonly attribute. The DS uses disabled combined with the ds-select--readonly class for visual differentiation. Unlike disabled, readonly should visually communicate that the value is set but not editable.
Required e label invisívelRequired and invisible label
Quando Required = true, adicione aria-required="true" no <select> — o asterisco visual (.ds-field__required) é decorativo (aria-hidden="true"). Quando Show Label = false, use aria-label no <select>. O Helper Text deve ser vinculado via aria-describedby.When Required = true, add aria-required="true" to the <select> — the visual asterisk (.ds-field__required) is decorative (aria-hidden="true"). When Show Label = false, use aria-label on the <select>. Helper Text should be linked via aria-describedby.

RelacionadosRelated