Button
Material Design 3 button component with multiple variants and sizes
Button
Buttons allow users to take actions with a single tap. @duskmoon-dev/core provides a complete set of Material Design 3 button variants.
Basic Usage
Basic Button
<button class="btn btn-primary">Primary Button</button>Variants
Filled Buttons
Filled buttons have the most visual impact and should be used for primary actions.
Filled Buttons
<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-tertiary">Tertiary</button>
<button class="btn btn-accent">Accent</button>
<button class="btn btn-neutral">Neutral</button>
<button class="btn btn-base">Base</button>Outlined Buttons
Outlined buttons are medium-emphasis buttons. They’re used for important but not primary actions.
Outlined Buttons
<button class="btn btn-outlined">Outlined</button>
<button class="btn btn-outlined btn-primary">Outlined Primary</button>
<button class="btn btn-outlined btn-secondary">Outlined Secondary</button>Text Buttons
Text buttons are used for low-priority actions, such as “Cancel” or “Learn More”.
Text Buttons
<button class="btn btn-text">Text Button</button>
<button class="btn btn-text btn-primary">Text Primary</button>Tonal Buttons
Tonal buttons use the theme’s container colors for a subtle but noticeable effect.
Tonal Buttons
<button class="btn btn-tonal">Tonal</button>
<button class="btn btn-tonal btn-primary">Tonal Primary</button>
<button class="btn btn-tonal btn-secondary">Tonal Secondary</button>Semantic Colors
Use semantic colors for user feedback:
Semantic Color Buttons
<button class="btn btn-success">Success</button>
<button class="btn btn-error">Error</button>
<button class="btn btn-warning">Warning</button>
<button class="btn btn-info">Info</button>Semantic colors work with all variants:
Semantic Colors with Variants
<button class="btn btn-outlined btn-success">Success Outlined</button>
<button class="btn btn-text btn-error">Error Text</button>
<button class="btn btn-tonal btn-warning">Warning Tonal</button>Sizes
Three sizes are available:
Button Sizes
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary btn-md">Medium (default)</button>
<button class="btn btn-primary btn-lg">Large</button>Icon Buttons
Buttons with Icons
Add icons alongside text:
Buttons with Icons
<button class="btn btn-primary">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
Add Item
</button>
<button class="btn btn-outlined">
Download
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
</button>Icon-Only Buttons
For compact interfaces, use icon-only buttons:
Icon-Only Buttons
<button class="btn btn-icon btn-primary">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<button class="btn btn-icon btn-icon-sm btn-outlined">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
</button>
<button class="btn btn-icon btn-icon-lg btn-tonal">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
</button>States
Disabled State
Disabled buttons are non-interactive:
Disabled Buttons
<button class="btn btn-primary" disabled>Disabled</button>
<button class="btn btn-outlined" disabled>Disabled Outlined</button>
<button class="btn btn-text" disabled>Disabled Text</button>Loading State
Use the btn-loading class to show a loading spinner. The text is hidden and a spinner appears in its place:
Loading Buttons
<button class="btn btn-primary btn-loading">Loading</button>
<button class="btn btn-secondary btn-loading">Loading</button>
<button class="btn btn-outlined btn-loading">Loading</button>
<button class="btn btn-tonal btn-loading">Loading</button>The loading state can be combined with any button variant and size:
Loading Button Sizes
<button class="btn btn-primary btn-sm btn-loading">Small</button>
<button class="btn btn-primary btn-md btn-loading">Medium</button>
<button class="btn btn-primary btn-lg btn-loading">Large</button>Block Buttons
Full-width buttons:
Block Button
<button class="btn btn-primary btn-block">Block Button</button>Button Groups
Group related buttons together:
Button Group
<div class="flex gap-2">
<button class="btn btn-text">Cancel</button>
<button class="btn btn-outlined">Save Draft</button>
<button class="btn btn-primary">Publish</button>
</div>Composing action components
Button remains the visual foundation for action triggers. Dropdown triggers and FAB / Speed Dial actions compose .btn with their component-specific classes rather than copying button colors, focus, loading, or disabled behavior.
When using individual imports for a FAB, import both styles:
@import "@duskmoon-dev/core/components/button";
@import "@duskmoon-dev/core/components/fab";
Best Practices
Visual Hierarchy
Use button variants to create clear visual hierarchy:
- Primary action:
btn-primary(filled) - Secondary action:
btn-outlinedorbtn-tonal - Tertiary action:
btn-text
Visual Hierarchy Example
<div class="flex gap-2">
<button class="btn btn-text">Cancel</button>
<button class="btn btn-outlined">Save Draft</button>
<button class="btn btn-primary">Publish</button>
</div>Accessibility
- Always provide meaningful button text or
aria-labelfor icon buttons - Use semantic HTML
<button>elements - Ensure sufficient color contrast
- Support keyboard navigation (built-in)
Accessible Icon Button
<button class="btn btn-icon btn-primary" aria-label="Close dialog">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>Touch Targets
Ensure buttons are large enough for touch interfaces (minimum 44×44px):
Responsive Button for Touch
<button class="btn btn-primary btn-md md:btn-sm">
Responsive Button
</button>Framework Examples
React
interface ButtonProps {
variant?: 'primary' | 'outlined' | 'text' | 'tonal';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
onClick?: () => void;
}
export function Button({ variant = 'primary', size = 'md', children, ...props }: ButtonProps) {
return (
<button className={`btn btn-${variant} btn-${size}`} {...props}>
{children}
</button>
);
}
// Usage
<Button variant="primary" onClick={() => console.log('clicked')}>
Click Me
</Button>
Vue
<template>
<button :class="`btn btn-${variant} btn-${size}`" v-bind="$attrs">
<slot />
</button>
</template>
<script setup>
defineProps({
variant: {
type: String,
default: 'primary'
},
size: {
type: String,
default: 'md'
}
})
</script>
<!-- Usage -->
<Button variant="primary" @click="handleClick">
Click Me
</Button>
API Reference
Class Names
| Class | Description |
|---|---|
.btn |
Base button styles (required) |
.btn-primary |
Primary filled button (default) |
.btn-secondary |
Secondary filled button |
.btn-tertiary |
Tertiary filled button |
.btn-accent |
Accent color |
.btn-neutral |
Neutral color |
.btn-base |
Theme base color |
.btn-outlined |
Outlined button variant |
.btn-text |
Text button variant |
.btn-tonal |
Tonal button variant |
.btn-success |
Success semantic color |
.btn-error |
Error semantic color |
.btn-warning |
Warning semantic color |
.btn-info |
Info semantic color |
.btn-sm |
Small size |
.btn-md |
Medium size (default) |
.btn-lg |
Large size |
.btn-icon |
Icon-only button |
.btn-icon-sm |
Small icon button |
.btn-icon-lg |
Large icon button |
.btn-block |
Full-width button |
.btn-loading |
Loading state with spinner |
.btn-circle |
Circular button (1:1 aspect ratio) |
.btn-square |
Square button (1:1 aspect ratio) |
Combinations
You can combine classes for different effects:
Class Combinations
<!-- Outlined secondary button, large size -->
<button class="btn btn-outlined btn-secondary btn-lg">
Large Outlined Secondary
</button>
<!-- Tonal error button, small size -->
<button class="btn btn-tonal btn-error btn-sm">
Small Tonal Error
</button>Related Components
- Dropdown - Button-triggered disclosures
- FAB / Speed Dial - Floating actions composed with Button
- Swap - State indicators that can compose with a button
- Badge - Notification indicators
- Card - Container with actions
- Input - Form inputs