Button
Standalone component with a native button, typed inputs, signals, and content projection.
Design
Functional preview
Running with the native Angular component and HTML button.
Styles
Anatomy
2 Icon (optional) — 20px frame/icon on sm and 24px on md/lg.
3 Label (
.ds-button__label) — typography and color via Component tokens.4 Root padding — sm 8×8px, md 10×12px, lg 12×16px.
5 Label padding — additional 4px on the Label Frame for optical balance.
Sizes
| Size | Height | Font | Padding | Touch target |
|---|---|---|---|---|
Small (--sm) | 32px (component.button.height.sm) | component.button.label.font-size.sm | 8×8px (component.button.padding-y.sm × padding-x.sm) | 32px — meets WCAG 2.5.8 min (24px) |
Medium (--md) | 40px (component.button.height.md) | component.button.label.font-size.md | 10×12px (component.button.padding-y.md × padding-x.md) | 40px |
Large (--lg) | 48px (component.button.height.lg) | component.button.label.font-size.lg | 12×16px (component.button.padding-y.lg × padding-x.lg) | 48px — meets AAA 44px target |
States
States are handled via CSS pseudo-classes (:hover, :active, :focus-visible, [disabled]), not modifier classes.
| State | CSS trigger | Visual change | Token |
|---|---|---|---|
| Default | — | Primary fill | component.button.bg.brand.default |
| Hover | :hover | Darker fill | component.button.bg.brand.hover |
| Pressed | :active | Darkest fill | component.button.bg.brand.pressed |
| Focus | :focus-visible | 2px ring with 2px offset and focus-state colors | component.button.bg.brand.focus, component.button.content.color.brand.focus, component.button.focus-ring.* |
| Disabled | [disabled] | Muted bg + content, no pointer events | component.button.bg.brand.disabled, component.button.content.color.brand.disabled |
With icon
Icon only
Loading
Full width
Token mapping
Tokens consumed by the Brand variant. Other variants follow the same pattern using their respective color groups.
| Property | Token (Component) | CSS variable |
|---|---|---|
| height (sm) | component.button.height.sm | --ds-button-height-sm |
| height (md) | component.button.height.md | --ds-button-height-md |
| height (lg) | component.button.height.lg | --ds-button-height-lg |
| min-width (sm/md/lg) | component.button.min-width.{sm,md,lg} | --ds-button-min-width-* |
| padding-x (sm/md/lg) | component.button.padding-x.{sm,md,lg} | --ds-button-padding-x-* |
| padding-y (sm/md/lg) | component.button.padding-y.{sm,md,lg} | --ds-button-padding-y-* |
| gap (sm/md/lg) | component.button.gap.{sm,md,lg} | --ds-button-gap-* |
| radius / border-width | component.button.radius.default, component.button.border-width.default | --ds-button-radius-default, --ds-button-border-width-default |
| bg por estilo/estado | component.button.bg.{brand,toned,outline,ghost,success,danger}.* | --ds-button-bg-* |
| border color Outline | component.button.border-color.outline.* | --ds-button-border-color-outline-* |
| text/icon color | component.button.content.color.{style}.{state} | --ds-button-content-color-* |
| label typography | component.button.label.{font-size,line-height,font-weight,letter-spacing}.* | --ds-button-label-* |
| icon frame/size | component.button.icon.size.{sm,md,lg}, component.button.icon.stroke-width.{sm,md,lg} | --ds-button-icon-* |
| icon-only | component.button.icon-only-{width,padding}.{sm,md,lg} | --ds-button-icon-only-* |
| focus ring | component.button.focus-ring.radius.default, component.focus-ring.{width,color.default,color.success,color.error} | --ds-focus-ring-* + --ds-button-focus-ring-radius-default |
Toned variant
--ds-toned-background-default, --ds-toned-background-hover, --ds-toned-background-active) instead of opaque fills. This differs from Subtle/Muted patterns which use opaque background tokens. The translucent approach lets the Toned button adapt naturally to any surface color beneath it while maintaining a consistent brand tint.
Figma
The Figma component exposes the properties below in the panel. Visibility booleans sit immediately above the slot they control.
| Property | Type | Default | Options |
|---|---|---|---|
| Style | Variant | Brand | Brand, Toned, Outline, Ghost, Success, Danger |
| Size | Variant | Medium | Small (32px), Medium (40px), Large (48px) |
| State | Variant | Default | Default, Hover, Pressed, Focused, Disabled |
| Icon Only | Variant | false | Default (with label), Icon Only (square) |
| Loading | Boolean | false | true, false |
| Show Left Icon | Boolean | false | Toggles visibility for the left icon frame |
| Left Icon | Instance swap | Placeholder | Sets the left icon component |
| Show Right Icon | Boolean | false | Toggles visibility for the right icon frame |
| Right Icon | Instance swap | Placeholder | Sets the right icon component |
Usage
When to use
<a>) instead. Don't use buttons for inline text actions or when the visual weight would compete with the page's primary action.
| Style | Use for | Emphasis |
|---|---|---|
| Brand | Primary action on the page. One per section, ideally one per page. | Highest |
| Toned | Secondary actions that need visibility but shouldn't compete with Brand. | Medium |
| Outline | Secondary or tertiary actions. Pairs well next to a Brand button. | Medium |
| Ghost | Tertiary actions, toolbar actions, or close/dismiss buttons. | Low |
| Success | Confirming a positive outcome: approve, complete, publish. | Contextual |
| Danger | Destructive actions: delete, remove, revoke. Always requires confirmation. | Contextual |
Best practices
Content guidelines
| Rule | Example |
|---|---|
| Use verb + noun for clarity | "Save changes", "Add item", "Delete project" — not just "Submit" or "OK" |
| Use sentence case | "Save changes" — not "Save Changes" or "SAVE CHANGES" |
| Keep labels short (1–3 words) | "Export CSV" — not "Click here to export your data as CSV" |
| Be specific about destructive actions | "Delete account" — not "Delete" or "Remove" |
| Avoid generic labels | "Confirm order" — not "Click here" or "Yes" |
Icon-only buttons need aria-label | aria-label="Close dialog" — describes the action, not the icon |
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 { TisButton } from '@tis/angular/button'Template
<form (submit)="guardar()">
<tis-button type="submit" variant="brand">
Guardar alterações
</tis-button>
</form>Public contract
- Package
@tis/angular- Entrypoint
@tis/angular/button- Primitive
HTML button- Status
- Beta
Accessibility
Keyboard interaction
| Key | Action |
|---|---|
Tab | Moves focus to the button (or past it if disabled) |
Enter | Activates the button |
Space | Activates the button |
Disabled buttons ([disabled]) are removed from tab order automatically by the browser. Loading buttons should also set aria-disabled="true" to prevent interaction while preserving tab order.
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 size (48px) meets 44px touch target | ✓ |
| 1.4.3 Contrast (AA) | White text on Brand/Danger fill ≥ 4.5:1. Disabled exempt. | ✓ |
| 4.1.2 Name, Role, Value (A) | Use <button> element. Icon-only requires aria-label. | ✓ |
| 1.4.1 Use of Color (A) | Focused state has visible ring. Disabled has dimmed text + reduced opacity. | ✓ |
aria-label — required on icon-only buttons.aria-disabled="true" + aria-busy="true" — set on loading buttons.disabled — use the native attribute for truly disabled buttons (removed from tab order).
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.