Select
Seleciona um único valor de uma lista conhecida sem aceitar entrada de texto.
Design
Preview funcional
Executado com HTML e CSS estáveis do DS, sem runtime JavaScript do componente.
Anatomia
.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.
Padrão
Tamanhos
| Size | Height | Font | Padding | Touch target |
|---|---|---|---|---|
Small (--sm) | 32px (component.select.height.sm) | component.select.text.font-size.sm | component.select.padding-x.sm / component.field.padding-y.sm | 32px — meets WCAG 2.5.8 min (24px) |
Medium (--md) | 40px (component.select.height.md) | component.select.text.font-size.md | component.select.padding-x.md / component.field.padding-y.md | 40px |
Large (--lg) | 48px (component.select.height.lg) | component.select.text.font-size.lg | component.select.padding-x.lg / component.field.padding-y.lg | 48px — meets AAA 44px target |
Com ícone
Estados
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.
Error
Disabled
Readonly
| Figma property | Value / CSS trigger | Visual change | Token |
|---|---|---|---|
| State | Default | Neutral border | component.field.border-color.default |
| State | Hover / :hover | Darker border | component.field.border-color.hover |
| State | Focus / :focus-visible | 2px outline ring, component radius | component.field.border-color.focus, component.focus-ring.*, component.select.focus-ring.radius.default |
| State | Disabled / [disabled] | Muted bg + content, no pointer events | component.field.bg.disabled, component.field.value.color.disabled, component.field.placeholder.color.disabled |
| Error | True / .ds-select--error or .ds-field--error .ds-select | Red border and error focus ring | component.field.border-color.error, component.focus-ring.color.error |
| Error + State | True + Hover / .ds-select--error:hover | Darker red border | component.field.border-color.error-hover |
| Read-only | True / .ds-select--readonly + [disabled] | Readonly bg and content treatment; native select has no real readonly focus | component.field.bg.readonly, component.field.value.color.readonly |
Propriedades Figma
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
Show Label | Boolean | true | Exibe ou oculta o label row (incluindo asterisco de obrigatório) |
Label | Text | "Rótulo" | Texto do label (label/md) |
Required | Boolean | false | Exibe o asterisco * em feedback/error/content/default ao lado do label |
Show Helper Text | Boolean | true | Exibe ou oculta o texto auxiliar abaixo do controle |
Helper Text | Text | "Texto auxiliar" | Anotação em caption/sm (content/secondary) |
Uso
Quando usar
Boas práticas
<option value="" disabled selected>Choose a country</option>.Diretrizes de conteúdo
| Regra | Exemplo |
|---|---|
| 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 types | All 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> |
Relacionados
Implementação
- Status
- Estável
- Distribuição
- Pacote npm
Instalação
npm install ds-tispnpm add ds-tisyarn add ds-tisbun add ds-tisImportações
import 'ds-tis/css'Markup
<div class="ds-field">
<label class="ds-field__label" for="country">País</label>
<div class="ds-select ds-select--md">
<select class="ds-select__field" id="country" name="country">
<option value="" disabled selected>Selecione um país</option>
<option value="br">Brasil</option>
<option value="cl">Chile</option>
</select>
<span class="ds-select__arrow" aria-hidden="true"></span>
</div>
</div>Contrato da implementação Web
Mapeamento de tokens
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.
| Propriedade | Token Component | Variável CSS |
|---|---|---|
| bg | component.field.bg.{default|focus|filled|error|disabled|readonly} | --ds-field-bg-* |
| border color | component.field.border-color.{default|hover|focus|filled|error|disabled|readonly} | --ds-field-border-color-* |
| border width | component.field.border-width | --ds-field-border-width |
| content color | component.field.value.color.{default|disabled|readonly} | --ds-field-value-color-* |
| placeholder color | component.field.placeholder.color.{default|disabled} | --ds-field-placeholder-color-* |
| chevron | component.field.icon.{color|size|stroke-width}.* + component.field.icon-frame.padding-x.default | --ds-field-icon-*, --ds-field-icon-frame-padding-x-default |
| height | component.select.height.{sm|md|lg} | --ds-select-height-* |
| gap | component.field.gap.{sm|md|lg} | --ds-field-gap-* |
| padding | component.select.padding-x.* / component.field.padding-y.* | --ds-select-padding-x-* / --ds-field-padding-y-* |
| radius | component.field.radius | --ds-field-radius |
| focus ring | component.focus-ring.* + component.select.focus-ring.radius.default | --ds-focus-ring-* + --ds-select-focus-ring-radius-default |
| typography | component.field.text.* + component.form-field.{label|helper|required}.* | --ds-field-text-*, --ds-form-field-* |
Classes CSS
| Classe | Descrição |
|---|---|
ds-select | Elemento wrapper do select |
ds-select__field | O elemento nativo <select> |
ds-select__arrow | Indicador de seta dropdown customizado |
ds-select__icon | Ícone à esquerda dentro do wrapper |
ds-select--sm | Tamanho pequeno (altura 32px) |
ds-select--md | Tamanho médio (altura 40px, padrão) |
ds-select--lg | Tamanho grande (altura 48px) |
ds-select--error | Estado de erro com borda vermelha |
ds-select--disabled | Estado desabilitado (ou use o nativo disabled) |
ds-select--readonly | Estado visual somente leitura (combine com o nativo disabled) |
ds-field__error | Linha de erro com ícone automático e mensagem (exibida quando ds-field--error está definido) |
ds-field__label-row | Linha horizontal com label e asterisco de obrigatório |
ds-field__required | Asterisco * em feedback/error/content/default (decorativo, aria-hidden) |
ds-field--no-label | Oculta o label row quando Show Label = false |
ds-field--no-helper | Oculta o helper text quando Show Helper Text = false |
Acessibilidade
Interação por teclado
| Tecla | Ação |
|---|---|
Tab | Move o foco para o select |
Space / Enter | Abre o dropdown (nativo do navegador) |
Arrow Up / Arrow Down | Navega entre as opções |
Escape | Fecha o dropdown |
| Any letter | Pula para a primeira opção que começa com aquela letra |
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.
Accessibility
| Critério WCAG | Requisito | Status |
|---|---|---|
| 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. | ✓ |
.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.
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.
Responsabilidade da saída
Preserve a semântica do elemento nativo, nomes acessíveis, comportamento de teclado e foco visível.
Evidência de validação
Coberta pelo Storybook estável, testes do runtime público quando aplicável, cenários de teclado, responsividade e Axe.