
Button
- 8 installs
- 228 repo stars
- Updated June 30, 2026
- thedaviddias/ux-patterns-for-developers
Helps with ai & agent building tasks.
About
button is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- button
- AI & Agent Building
- AI-coding skill
Button by the numbers
- 8 all-time installs (skills.sh)
- Ranked #12,321 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thedaviddias/ux-patterns-for-developers --skill buttonAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 228 |
| Last updated | June 30, 2026 |
| Repository | thedaviddias/ux-patterns-for-developers ↗ |
What it does
Helps with ai & agent building tasks.
Files
Button
Trigger actions and submit forms
What it solves
Buttons are interactive elements that trigger actions or events when clicked or interacted with.
When to use
- To trigger an immediate action or event (e.g., "Save", "Delete", "Send")
- To submit a form
- To open or close interactive elements (modals, dialogs, menus)
- To toggle between states (e.g., play/pause, show/hide)
- To download files or content
- To navigate between steps in a multi-step process
When to avoid
- For navigation between pages (use links instead)
- When the action isn't immediately clear to users
- For text-only content that doesn't trigger an action
- When the interaction would be better served by a different component (e.g., checkbox, toggle switch)
- When multiple conflicting actions are grouped together
- When the action requires additional context that isn't immediately available
Implementation workflow
1. Confirm the pattern matches the problem and constraints before copying the example. 2. Start from the anatomy and examples in references/pattern.md, then choose the smallest viable variation. 3. Apply accessibility, performance, and interaction guardrails before layering visual polish. 4. Use the testing guidance to verify behavior across keyboard, screen reader, responsive, and failure scenarios.
Accessibility guardrails
ARIA Attributes
Required [ARIA attributes](/glossary/aria-attributes):
- Use
aria-labelfor icon-only buttons - Use
aria-pressedfor toggle buttons - Use
aria-expandedfor buttons that control expandable content - Use
aria-disabled="true"instead of thedisabledattribute - Use
aria-describedbyto associate additional descriptive text
Screen Reader Support
Implementation example:
<!-- Icon-only button with proper ARIA -->
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true">
<use href="#icon-close" />
</svg>
</button>
<!-- Toggle button with ARIA pressed state -->
<button type="button" aria-pressed="false">
<span>Dark mode</span>
</button>
<!-- Expandable content button -->
<button type="button" aria-expanded="false" aria-controls="content-1">
<span>Show more</span>
</button>Related patterns
- https://uxpatterns.dev/patterns/forms/toggle
- https://uxpatterns.dev/patterns/navigation/link
---
For full implementation detail, examples, and testing notes, see references/pattern.md.
Pattern page: https://uxpatterns.dev/patterns/forms/button
Button
Create accessible and user-friendly buttons with proper states, design patterns, and implementation guidelines.
URL: https://uxpatterns.dev/patterns/forms/button Source: apps/web/content/patterns/forms/button.mdx
---
Overview
Buttons are interactive elements that trigger actions or events when clicked or interacted with.
Use Cases
When to use:
- To trigger an immediate action or event (e.g., "Save", "Delete", "Send")
- To submit a form
- To open or close interactive elements (modals, dialogs, menus)
- To toggle between states (e.g., play/pause, show/hide)
- To download files or content
- To navigate between steps in a multi-step process
When not to use:
- For navigation between pages (use links instead)
- When the action isn't immediately clear to users
- For text-only content that doesn't trigger an action
- When the interaction would be better served by a different component (e.g., checkbox, toggle switch)
- When multiple conflicting actions are grouped together
- When the action requires additional context that isn't immediately available
Common scenarios and examples
- Primary actions: "Submit", "Save", "Continue"
- Secondary actions: "Cancel", "Back", "Reset"
- Destructive actions: "Delete", "Remove", "Clear All"
- Toggle actions: "Show More", "Expand/Collapse", "Play/Pause"
- Process actions: "Upload", "Download", "Export"
- Social actions: "Share", "Follow", "Like"
Benefits
- Provides clear, actionable interactions for users to accomplish tasks
- Maintains consistency in user interface interactions across the application
- Offers visual feedback and states (hover, focus, active, disabled) to enhance usability
- Supports accessibility through keyboard navigation and screen reader compatibility
- Reduces cognitive load by making actions immediately recognizable## Drawbacks
- Overuse can lead to UI clutter – Too many buttons in an interface can confuse users.
- Styling inconsistencies – Needs proper theming and responsive considerations for different screen sizes.
- Click area issues – If not sized properly, buttons may be difficult to tap on mobile.
- Lack of clear labels – Buttons without descriptive text (e.g., just an icon) can cause usability problems.
- Focus management – Requires proper
:focusstates for accessibility and keyboard users.
Anatomy
flowchart TB
Container[Container Element] -->|contains| Content[Content Area]
Content --> Icon[Icon <optional>]
Content --> Label[Label Text]
Content --> LoadingSpinner[Loading Spinner <optional>]Component Structure
1. Container
- The root button element that wraps all other components
- Handles click events and keyboard interactions
- Manages focus states and accessibility attributes
- Contains variants for different button styles (default, destructive, outline, etc.)
2. Label Text
- The button label communicates the action that will occur
- Should be clear, concise, and action-oriented
- Must maintain proper contrast ratio with the background
3. Icon (Optional)
- Icons can be added to clarify an action
- Should be the same color as the text
- Placed on the left side of the label by default
- Size should be proportional to text (default 16x16px)
- Should include proper ARIA labels when used alone
4. Loading State (Optional)
- Visual indicator for async operations
- Replaces or overlays the button content
- Should maintain the button's original width
- Prevents multiple clicks during loading
- Typically uses a spinner or progress indicator
- Add loading text alongside spinners (e.g., "Saving..." vs just a spinner)
- Responsive considerations: When button text is hidden on mobile (icon-only), preserve context through:
- Keep the icon visible with an inline spinner overlay
- Use
aria-liveregions to announce status changes - Consider tooltips or micro-animations to indicate what's loading
- Maintain
aria-labelthat includes the action being performed
5. Visual States
- Default: Normal state
- Hover: Visual feedback on mouse over
- Focus: Keyboard navigation indicator
- Active: Pressed state
- Disabled: Indicates non-interactive state
- Loading: Shows processing state
Summary of Components
| Component | Required? | Purpose |
|---|---|---|
| Container | ✅ Yes | Wraps all button elements and handles interactions. |
| Label Text | ✅ Yes | Communicates the action that the button performs. |
| Icon | ❌ No | Enhances clarity of the action (typically placed left). |
| Loading State | ❌ No | Indicates an ongoing process (e.g., saving, submitting). |
| Visual States | ✅ Yes | Defines button interactions (hover, focus, active, etc.). |
Button Variations
Content Composition
1. Text Only
2. Icon Only
<button type="button" aria-label="Settings">
<svg aria-hidden="true">...</svg>
</button>3. Icon + Text
- Left Icon
<button type="button">
<svg aria-hidden="true">...</svg>
<span>Button</span>
</button>- Right Icon
<button type="button">
<span>Button</span>
<svg aria-hidden="true">...</svg>
</button>4. Double Icon
<button type="button">
<svg aria-hidden="true">...</svg>
<span>Button</span>
<svg aria-hidden="true">...</svg>
</button>5. With Counter/Badge
<button type="button">
<span>Messages</span>
<span class="counter">18</span>
</button>6. With Command/Shortcut
<button type="button">
<span>Print</span>
<span class="shortcut">⌘P</span>
</button>Profile Variations
7. With Avatar
<button type="button">
<img src="avatar.jpg" alt="" />
<span>@username</span>
</button>Action Groups
8. Button Groups
- Horizontal Group
<div role="group" aria-label="Text alignment">
<button type="button">Left</button>
<button type="button">Center</button>
<button type="button">Right</button>
</div>- Vertical Group
<div role="group" aria-label="Actions" class="vertical">
<button type="button">Files</button>
<button type="button">Media</button>
</div>9. Split Buttons
<div class="split-button">
<button type="button">Action</button>
<button type="button" aria-label="More options">▼</button>
</div>State Variations
10. Loading States
<!-- Standard loading with text -->
<button type="button" aria-busy="true">
<svg class="spinner" aria-hidden="true">...</svg>
<span>Loading...</span>
</button>
<!-- Responsive: Icon-only on mobile with preserved context -->
<button type="button" aria-busy="true" aria-label="Save document">
<svg class="icon-save" aria-hidden="true">...</svg>
<span class="text-desktop-only">Save</span>
<svg class="spinner-overlay" aria-hidden="true">...</svg>
<span class="sr-only">Saving...</span>
</button>11. Toggle States
<button type="button" aria-pressed="false">
<span>Pin</span>
</button>Social Variations
12. Social Login
<button type="button" class="social-login google">
<svg aria-hidden="true">...</svg>
<span>Login with Google</span>
</button>Special Purpose
13. Upload Button
<button type="button" class="upload">
<svg aria-hidden="true">...</svg>
<span>Upload image</span>
<span class="status">No image uploaded</span>
</button>14. Numeric Indicator
<button type="button">
<span>Star</span>
<span class="count">729</span>
</button>Each variation can be combined with different visual styles (primary, secondary, outline, ghost) and sizes (small, medium, large) to create the full range of possible button components.
Examples
Live Preview
Basic Implementation
<!-- Small Button -->
<button type="button" class="button-sm">Small</button>
<!-- Default Size Button -->
<button type="button">Default</button>
<!-- Large Button -->
<button type="button" class="button-lg">Large</button>
<!-- Icon-only Button -->
<button type="button" aria-label="Settings">
<svg aria-hidden="true">
<use href="#icon-settings" />
</svg>
</button>Form Submit Button
<form>
<!-- Form fields here -->
<button type="submit" class="button button-primary" data-loading="false">
<span class="button-text">Submit Form</span>
<svg class="icon spinner hidden" aria-hidden="true">
<use href="#icon-loading" />
</svg>
</button>
</form>Best Practices
Content
Do's ✅
- Use action verbs that describe what the button does (eg: "Save" instead of "Submit")
- Keep button labels concise and clear
- Be consistent with button labeling across the application
- Include loading text when appropriate ("Saving..." vs "Save")
- Use sentence case for button labels (e.g., "Save Changes")
Don'ts ❌
- Don't use vague labels like "Click Here" or "Submit"
- Don't use inconsistent terminology
- Don't write overly long button labels
- Don't use technical jargon in button labels
- Don't mix different cases in button labels
Accessibility
Do's ✅
- Use descriptive labels that clearly communicate the action [^describe-buttons]
- Provide visual feedback for all interactive states
- Ensure keyboard navigation works properly
- Include loading states for asynchronous actions
- Don't pass the
disabledattribute to buttons, instead usearia-disabled. You would risk disrupting the keyboard navigation flow as this would reset focus on the button. - Use descriptive loading states with both text and visual indicators
- When buttons become icon-only on mobile, maintain context during loading with
aria-liveannouncements - Preserve the original icon during loading states for icon-only buttons
- Use
aria-busy="true"during async operations to inform assistive technologies
Don'ts ❌
- Don't rely solely on color to communicate button states
- Don't disable browser focus indicators without providing alternatives
- Don't use button elements for navigation (use links instead)
- Don't auto-focus destructive actions
- Don't remove focus styles
Visual Design
Do's ✅
- Use the same button style for the same action throughout the application
- Make buttons finger-friendly for mobile users (minimum 44x44px touch target)
- Use appropriate visual hierarchy (primary, secondary, tertiary buttons)
- Maintain consistent spacing between button groups
- Use appropriate color contrast ratios (WCAG 2.2 AA compliance)
- Include hover and focus states for interactive feedback
- Keep icon and text alignment consistent
- Maintain consistent padding and height across similar buttons
- Scale button size appropriately for different viewport sizes
Don'ts ❌
- Don't have more than one primary action button on the screen at a time
- Don't use a dark pattern when you don't want users to take a certain action
- Don't mix different button styles for the same action type
- Don't use colors that conflict with your application's color scheme
- Don't make disabled buttons look interactive
- Don't use inconsistent corner radius within button groups
- Avoid having buttons looking like links or vice versa
- Don't use spinners without descriptive text
- Don't replace icon-only buttons entirely with spinners—keep the icon visible for context
- Don't assume loading indicators alone convey what's happening on mobile devices
Mobile & Touch Considerations
Do's ✅
- Place primary actions within thumb-friendly zones
- Use full-width buttons for important actions on mobile
- Implement haptic feedback for touch interactions
- Maintain sufficient spacing between touch targets (minimum 8px)
- For icon-only buttons on mobile, keep the icon visible during loading with inline spinners
- Provide status feedback through subtle animations or micro-interactions when text is hidden
- Consider using
aria-liveregions for important state changes in icon-only buttons
Don'ts ❌
- Don't place critical actions in hard-to-reach corners
- Don't rely solely on hover states for mobile feedback
- Don't make touch targets smaller than 44x44px
- Don't crowd multiple buttons together on mobile views
Layout & Positioning
Do's ✅
- Place primary action buttons in prominent, easily accessible locations
- Align buttons consistently within forms and dialogs
- Group related buttons together
- Consider mobile touch targets (minimum 44x44px)
Don'ts ❌
- Don't position buttons where they might be accidentally clicked
- Don't hide important actions behind dropdown menus
- Don't place buttons in unexpected locations (e.g., footer)
Accessibility
ARIA Attributes
Required [ARIA attributes](/glossary/aria-attributes):
- Use
aria-labelfor icon-only buttons - Use
aria-pressedfor toggle buttons - Use
aria-expandedfor buttons that control expandable content - Use
aria-disabled="true"instead of thedisabledattribute - Use
aria-describedbyto associate additional descriptive text
Screen Reader Support
Implementation example:
<!-- Icon-only button with proper ARIA -->
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true">
<use href="#icon-close" />
</svg>
</button>
<!-- Toggle button with ARIA pressed state -->
<button type="button" aria-pressed="false">
<span>Dark mode</span>
</button>
<!-- Expandable content button -->
<button type="button" aria-expanded="false" aria-controls="content-1">
<span>Show more</span>
</button>Keyboard Navigation
- Buttons must be focusable and activated with both Enter and Space keys
- Focus order should follow a logical sequence
- Focus states must be clearly visible
- Avoid removing focus outlines without providing alternatives
- Maintain focus after interactions (e.g., after closing a modal)
Testing Guidelines
Functional Testing
Should ✓
- [ ] Show a loader when the button is submitting a form
- [ ] Disable the button during form submission to prevent double submissions
- [ ] Handle click events and trigger the appropriate action
- [ ] Maintain proper visual states (hover, focus, active, disabled)
- [ ] Support keyboard interaction (Enter and Space keys)
- [ ] Preserve button width when switching between normal and loading states
- [ ] Reset to initial state after operation completion
Accessibility Testing
Should ✓
- [ ] Be focusable and have visible focus indicators
- [ ] Have proper ARIA labels, especially for icon-only buttons
- [ ] Maintain sufficient color contrast ratios (WCAG 2.2 AA)
- [ ] Support screen reader announcements of button state changes
- [ ] Be operable with keyboard navigation
- [ ] Communicate loading states to assistive technologies
- [ ] Have appropriate touch target sizes (minimum 44x44px)
Visual Testing
Should ✓
- [ ] Maintain consistent styling across different variants (primary, secondary, destructive)
- [ ] Display icons with correct alignment and spacing
- [ ] Show proper visual feedback for all interactive states
- [ ] Render correctly across different viewport sizes
- [ ] Handle text overflow appropriately
- [ ] Display loading spinners centered within the button
- [ ] Maintain proper padding and margins in all states
Performance Testing
Should ✓
- [ ] Render without layout shifts
- [ ] Handle rapid click events appropriately
- [ ] Maintain smooth transitions between states
- [ ] Load icons and spinners efficiently
- [ ] Function without JavaScript (progressive enhancement)
Testing Tools
- Accessibility: WAVE, aXe, or Lighthouse
- SEO: Google's Rich Results Test
- Performance: Chrome DevTools Performance panel
- Visual Regression: Percy or Chromatic
- Cross-browser: BrowserStack or Sauce Labs
Design Tokens
These design tokens follow the Design Tokens Format specification and can be used with various token transformation tools to generate platform-specific variables.
Button Tokens in DTF Format
{
"$schema": "https://design-tokens.org/schema.json",
"button": {
"sizing": {
"height": {
"sm": { "value": "2.25rem", "type": "dimension" },
"md": { "value": "2.5rem", "type": "dimension" },
"lg": { "value": "2.75rem", "type": "dimension" }
},
"paddingX": {
"sm": { "value": "0.75rem", "type": "dimension" },
"md": { "value": "1rem", "type": "dimension" },
"lg": { "value": "2rem", "type": "dimension" }
},
"iconSize": { "value": "1rem", "type": "dimension" },
"iconGap": { "value": "0.5rem", "type": "dimension" },
"touchTarget": {
"value": "2.75rem",
"type": "dimension",
"description": "44px minimum [touch target](/glossary/touch-targets)"
}
},
"typography": {
"fontFamily": { "value": "{font.family.sans}", "type": "fontFamily" },
"fontWeight": { "value": "600", "type": "fontWeight" },
"fontSize": {
"sm": { "value": "0.875rem", "type": "dimension" },
"md": { "value": "1rem", "type": "dimension" },
"lg": { "value": "1.125rem", "type": "dimension" }
}
},
"border": {
"radius": {
"sm": { "value": "0.375rem", "type": "dimension" },
"md": { "value": "0.5rem", "type": "dimension" },
"lg": { "value": "0.75rem", "type": "dimension" },
"pill": { "value": "999px", "type": "dimension" }
},
"width": { "value": "1px", "type": "dimension" }
},
"variants": {
"primary": {
"background": {
"default": { "value": "{color.primary.600}", "type": "color" },
"hover": { "value": "{color.primary.700}", "type": "color" },
"active": { "value": "{color.primary.800}", "type": "color" },
"disabled": { "value": "{color.primary.200}", "type": "color" }
},
"text": {
"default": { "value": "{color.white}", "type": "color" },
"disabled": { "value": "{color.primary.100}", "type": "color" }
}
},
"secondary": {
"background": {
"default": { "value": "{color.gray.100}", "type": "color" },
"hover": { "value": "{color.gray.200}", "type": "color" },
"active": { "value": "{color.gray.300}", "type": "color" },
"disabled": { "value": "{color.gray.50}", "type": "color" }
},
"text": {
"default": { "value": "{color.gray.900}", "type": "color" },
"disabled": { "value": "{color.gray.400}", "type": "color" }
}
},
"destructive": {
"background": {
"default": { "value": "{color.red.600}", "type": "color" },
"hover": { "value": "{color.red.700}", "type": "color" },
"active": { "value": "{color.red.800}", "type": "color" },
"disabled": { "value": "{color.red.200}", "type": "color" }
},
"text": {
"default": { "value": "{color.white}", "type": "color" },
"disabled": { "value": "{color.red.100}", "type": "color" }
}
},
"outline": {
"border": {
"default": { "value": "{color.gray.300}", "type": "color" },
"hover": { "value": "{color.gray.400}", "type": "color" },
"active": { "value": "{color.gray.500}", "type": "color" },
"disabled": { "value": "{color.gray.200}", "type": "color" }
},
"text": {
"default": { "value": "{color.gray.900}", "type": "color" },
"disabled": { "value": "{color.gray.400}", "type": "color" }
}
}
},
"states": {
"focusRing": {
"width": { "value": "2px", "type": "dimension" },
"offset": { "value": "2px", "type": "dimension" },
"color": { "value": "{color.primary.200}", "type": "color" }
},
"loadingSpinner": {
"size": { "value": "1rem", "type": "dimension" },
"borderWidth": { "value": "2px", "type": "dimension" }
}
}
}
}Frequently Asked Questions
` and manage ARIA attributes appropriately.", }, { question: "What are the different types of buttons?", answer: "Common types include primary buttons for main actions, secondary buttons for less important actions, and tertiary buttons for minimal emphasis. Variants like text, contained, and outlined buttons offer different visual styles.", }, { question: "What are common mistakes to avoid when implementing buttons?", answer: "Avoid using non-semantic elements for buttons, neglecting accessibility features, overloading buttons with too many styles, and failing to provide clear visual feedback for different states.", }, ]} />
Related Patterns
Resources
References
- WCAG 2.2 - Accessibility baseline for keyboard support, focus management, and readable state changes.
- MDN button element - Native button semantics, activation behavior, and form integration.
Guides
- MDN WAI-ARIA basics - Guidance on when to rely on native HTML and when to introduce ARIA roles and states.
Articles
- Smashing Magazine: Designing efficient web forms - Field-level usability guidance for labels, grouping, defaults, and submission flows.
NPM Packages
- `@radix-ui/react-slot` - Polymorphic slotting for composable buttons and interactive surfaces.
- `react-aria-components` - Headless accessible components covering many form and overlay patterns.
- `framer-motion` - Motion primitives for affordance, feedback, and progressive reveal.