Select
A standalone Angular component over a native select, with a complete Form Field, validation, and ControlValueAccessor.
Design
Functional preview
Running with the native Angular component and HTML select + Angular Forms.
Anatomy
.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.
Default
Sizes
| 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 |
With icon
States
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
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 |
Figma properties
| Property | Type | Default | Description |
|---|---|---|---|
Show Label | Boolean | true | Shows or hides the label row (including required asterisk) |
Label | Text | "Rótulo" | Label text (label/md) |
Required | Boolean | false | Shows * in feedback/error/content/default next to the label |
Show Helper Text | Boolean | true | Shows or hides the helper text below the control |
Helper Text | Text | "Texto auxiliar" | Caption/sm annotation (content/secondary) |
Usage
When to use
Best practices
<option value="" disabled selected>Choose a country</option>.Content guidelines
| Rule | Example |
|---|---|
| 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> |
Related
When to choose this output
Choose this native Angular output when the application already uses Angular. It consumes the same DS CSS and has no dependency on the Web runtime or React adapters.
Implementation
- Status
- Beta
- Distribution
- Validated Angular tarball
Installation
npm install ./dist/tis-angular-0.0.0-beta.0.tgz ds-tispnpm add ./dist/tis-angular-0.0.0-beta.0.tgz ds-tisyarn add ./dist/tis-angular-0.0.0-beta.0.tgz ds-tisbun add ./dist/tis-angular-0.0.0-beta.0.tgz ds-tisDS styles
@import "ds-tis/css";Angular imports
import { FormsModule } from '@angular/forms'
import { TisSelect, TisSelectIcon } from '@tis/angular/select'Template
<tis-select
name="country"
label="País"
[(ngModel)]="country"
helperText="Selecione o país de residência."
[required]="true"
>
<svg tisSelectIcon aria-hidden="true">…</svg>
<option value="br">Brasil</option>
<option value="cl">Chile</option>
</tis-select>Public contract
- Package
@tis/angular- Entrypoint
@tis/angular/select- Primitive
HTML select + Angular Forms- Status
- Beta
Accessibility
Keyboard interaction
| Key | Action |
|---|---|
Tab | Moves focus to the select |
Space / Enter | Opens the dropdown (browser-native) |
Arrow Up / Arrow Down | Navigates options |
Escape | Closes dropdown |
| Any letter | Jumps to first option starting with that letter |
All keyboard interactions are handled natively by the <select> element. No custom JavaScript is required. Disabled selects are removed from tab order automatically.
Accessibility
| WCAG criterion | Requirement | 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) 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 = 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.
Output responsibility
Preserve native button semantics, submit behavior, accessible names, disabled state, and visible focus.
Validation evidence
Covered by its independent Storybook output plus browser, responsive, keyboard, Axe, and bundle checks.