Use this as the source of truth when translating designs to code. Every Figma variant maps to a CSS class and HTML element.
Naming Conventions
- Figma uses PascalCase for property names:
Type=Primary,State=Hover,Size=MD - CSS classes use kebab-case:
.btn-primary,.btn-md - State modifiers use BEM-style:
.is-active,.is-error,:hover,:focus - Semantic HTML first — use the right element before adding ARIA
Hover/focus states are never separate HTML elements — always CSS pseudo-classes. The Figma variants exist for visual documentation only.
Component Mappings
| Component | Figma Variant | CSS Class | HTML Element |
|---|---|---|---|
| Button | Type=Primary, State=Default, Size=MD | .btn.btn-md.btn-primary |
button.btn.btn-md.btn-primary |
| Button | Type=Secondary, State=Default, Size=MD | .btn.btn-md.btn-secondary |
button.btn.btn-md.btn-secondary |
| Button | Type=Ghost, State=Default, Size=SM | .btn.btn-sm.btn-ghost |
button.btn.btn-sm.btn-ghost |
| Button | Type=Danger, State=Default, Size=MD | .btn.btn-md.btn-danger |
button.btn.btn-md.btn-danger |
| Button | State=Hover | — (use :hover pseudo-class) |
— |
| Button | State=Focus | :focus-visible + 3px ring |
— |
| Button | State=Disabled | [disabled] or aria-disabled |
— |
| Input | State=Default | .input |
input.input |
| Input | State=Error | .input.is-error + aria-invalid |
input.input.is-error |
| Input | State=Focus | .input:focus |
— |
| Input | State=Disabled | .input[disabled] |
— |
| Badge | Color=Brand, Style=Pill | .badge.badge-brand.badge-pill |
span.badge.badge-brand.badge-pill |
| Badge | Color=Error, Style=Default | .badge.badge-error |
span.badge.badge-error |
| Badge | Color=Success | .badge.badge-success |
span.badge.badge-success |
| Alert | Type=Warning | .alert.alert-warning + role="alert" |
div.alert.alert-warning |
| Alert | Type=Success | .alert.alert-success + role="status" |
div.alert.alert-success |
| Alert | Type=Error | .alert.alert-error + role="alert" |
div.alert.alert-error |
| Modal | Type=Confirmation | .modal + role="dialog" |
div.modal |
| Modal | Type=Destructive | .modal + .btn-danger footer |
div.modal |
| Dropdown | Style=Simple, State=Open | .dropdown.is-open |
div.dropdown |
| TabBar | Theme=Light, State=Active | .tabs .tab.is-active |
— |
| TabBar | Theme=Dark | .tabs.tabs-dark |
— |
| TabBar | Style=Pill | .tabs.tabs-pill |
— |
| Navbar | Theme=Light | .navbar |
nav.navbar |
| Navbar | Theme=Dark | .navbar.navbar-dark |
nav.navbar.navbar-dark |
| Avatar | Size=MD, Shade=Dark, Color=Brand | .avatar.avatar-md.avatar-brand-dark |
span.avatar |
| Checkbox | State=Checked | .checkbox:checked |
input[type=checkbox] |
| Radio | State=Selected | .radio:checked |
input[type=radio] |
| Toggle | State=On | .toggle.is-on + role="switch" aria-checked="true" |
input.toggle |
| Card | Default | .card |
div.card |
| StatCard | Trend Up | .stat-card .trend-up |
div.stat-card |
| DataTable | Density=Comfortable | .data-table.density-comfortable |
table.data-table |
| FormLayout | Two Column | .form-layout.cols-2 |
div.form-layout.cols-2 |
| IconButton | Style=Ghost, Size=MD | .btn.btn-icon.btn-ghost.btn-md |
button.btn.btn-icon |
| CountBadge | Shade=Dark, Color=Brand | .badge.badge-brand (pill) |
span.badge |
| Breadcrumb | Separator=Slash | .breadcrumb |
nav.breadcrumb |