Buttons
These guidelines define how buttons should look, behave, and be implemented across all products. The goal is to ensure a consistent, accessible, and intuitive user experience while maintaining flexibility and scalability.
In applications that use TUM AET UI, use its Button component: it implements these variants, states, and sizes.
✅ TL;DR​
- Use the correct variant for every button
- Only one primary button per page
- Destructive buttons always open a confirmation
- Use spacing and corner radius consistently
- Icon buttons must be circular and have an accessible name (
aria-label) and a tooltip - Targets are at least 24 Ă— 24 px, better 44 Ă— 44 px on touch devices
- Don’t use links for actions or buttons for navigation
- Avoid visual overload – use menus for secondary actions
🧩 Button Variants​
Use semantic variants based on the button’s purpose, not its appearance.
Semantic variants define the function of a button in the context of the UI, such as the ones below. Not all the following variants are needed in all applications.
Colors / Severity​
| Variant | Use Case | Typical Colors | Notes |
|---|---|---|---|
| Primary | Main action on a page (e.g., “Save”, “Submit”) | Brand color background, white text | - One per page or screen - High contrast and visibility - Never used for destructive actions |
| Secondary | Secondary action (e.g., “Cancel”, “Back”) | Neutral background or border | - Visual fallback to primary - Useful for “Back” or “Cancel” - Should not compete visually with primary |
| Destructive / Danger | Dangerous or irreversible actions (e.g., “Delete”) | Red background or border | - Always trigger a confirmation overlay or modal before the action is executed - Be clearly labeled (“Delete”, not “Confirm” or “OK”) - Must never be the primary button unless it’s the only available action |
| Success | Successful Actions (e.g., "Confirm") | Green background or border | - Signals that an action will positively confirm or resolve something (e.g., “Mark as Done”) - Used after success feedback (e.g., “Continue” after a successful form) |
| Disabled | Non-interactive, inactive state of any variant | Muted text, subdued background or border | - Be visually muted (e.g., gray background, 50–70% opacity) - Explain why the button is disabled, ideally with visible hint text - Use the disabled attribute: the button is then neither clickable nor keyboard-focusable- If users must be able to focus it (e.g., to read a tooltip with the reason), use aria-disabled="true" instead and ignore clicks in the handler- Have no hover/active interaction - Never hide disabled buttons — they should show users which actions are currently unavailable. |
Additional Button Variants
These buttons are often only used in edge cases. This list is not complete. You may want to have more/other variants.
| Variant | Use Case | Typical Colors | Notes |
|---|---|---|---|
| Tertiary | Less important or contextual actions | Text-only, no background | - Very low priority - Perfect for “Show more”, “Edit” - Works well inline with text or in lists |
| Accent | Emphasized but not primary (e.g., “Upgrade”, “Info”) | Custom accent color | - Used to draw attention to helpful but non-essential features (e.g., upsells) - Should feel optional, not mandatory |
| Info | For actions that guide the user without commitment (e.g., "Done") | Blue/gray tone or primary color, icon optional | - Used for helpful or guiding interactions (e.g., “Why?”, “Learn more”) - Can contain icons - Should never block user flow or be required to continue |
| White / Transparent | Use on dark backgrounds (e.g., hero banners, modals) | White text, transparent or subtle border | - Only for dark surfaces (e.g., hero sections, dark modals) - Text must be white and high contrast - Should have hover/focus states to ensure accessibility |
Use semantic color tokens like color.button.primary.bg or color.button.destructive.hover. See Color Guidelines
States​
| State | What to Use |
|---|---|
| Default | Use the token for the current variant |
| Hover | Slightly darker/lighter than base |
| Active | Higher contrast or inset shadow |
| Focus | Always show a visible focus ring for keyboard users (:focus-visible), e.g., a 2px outline with at least 3:1 contrast to the surrounding colors |
| Disabled | Muted background, cursor not-allowed, no interaction |
🚦 Button Limits & Hierarchy​
To maintain clarity:
| Rule | Recommendation |
|---|---|
| Max visible buttons per section | 3–4 |
| Max primary button per page | 1 |
| Max secondary buttons | 2-3 |
| Max destructive buttons | 1, always ask for confirmation |
| Use overflow or menus if… | >3 actions or low-priority options |
Avoid overwhelming users. Use dropdowns, kebab menus (⋮), or “More…” links for less-used actions.
📏 Size & Target Area​
| Rule | Recommendation |
|---|---|
| Minimum target size | 24 Ă— 24 CSS px for every clickable area (WCAG 2.2, 2.5.8, Level AA), including icon buttons |
| Smaller targets | Only if a 24 px circle centered on each small target overlaps neither another target nor the circle of another small target, so leave enough space between them |
| Touch / primary actions | Prefer 44 Ă— 44 CSS px (WCAG 2.5.5, Level AAA), especially on mobile |
| Visual vs. clickable size | The clickable area may be larger than the visible button (e.g., padding around an icon), but never smaller |
⚙️ Possible Button Properties​
Your button component could potentially include the following props to ensure complete flexibility:
| Prop | Type | Description |
|---|---|---|
| variant | string/enum (filled, outlined, text) | Defines the button style |
| severity | string/enum (primary, secondary, tertiary, destructive) | Defines the button color |
| size | string (sm, md, lg) | Controls padding and font size |
| label | string | Button label/text |
| type | button | submit | reset | Native button type; default to button so that buttons inside forms don’t submit them by accident |
| icon | JSX/Icon component | Optional icon |
| iconPosition | start | end | Icon placement |
| disabled | boolean | Disables the button |
| onClick | function | Click handler |
| aria-label | string | For accessibility (especially for icon-only) |
| fullWidth | boolean | Button stretches to parent width |
| loading | boolean | Shows loading indicator and disables interaction |
🔗 Link Guidelines​
| Rule | Recommendation |
|---|---|
| Appearance | Blue text, underlined by default |
| Hover | Darker blue or underline (if not always shown) |
| In buttons? | Only if styled as tertiary buttons |
| Navigation links | Use semantic <a> tags, never fake links via <button> |
| Non-nav actions | Use buttons, not links (e.g., “Submit”, “Retry”) |
Links that look like buttons confuse users and hurt accessibility. Use one visual language per function. If you still need a button to redirect, please use the redirect icon: