Skip to content

Button Component

The DsButton component is a flexible button component that wraps Vuetify's v-btn with design system conventions and theming.

Overview

DsButton provides a comprehensive button solution with multiple variants, sizes, and states. It supports Material Design 3 styling, icon-only buttons, loading states, and full accessibility features.

Interactive Demo

Button Playground

Customize the button using the controls below to see different variants, colors, and sizes.

Controls

elevated

Button style variant

primary

Color from design tokens

md

Button size

Render as icon-only button (48px × 48px)

Show loading spinner

Disable button interaction

Text to display on button

Code
<template>
  <DsButton>
    Click Me
  </DsButton>
</template>

Variants

The button supports five Material Design 3 variants:

  • Elevated (default): Filled button with shadow elevation, best for important primary actions
  • Flat: Filled button without shadow, for high-emphasis actions in constrained spaces
  • Tonal: Subtle filled button with background tint, for medium-emphasis actions
  • Outlined: For secondary actions that need emphasis without solid fill
  • Text: For tertiary or low-emphasis actions

Sizes

Buttons come in three sizes:

  • sm (small): Compact buttons for tight spaces
  • md (medium, default): Standard button size for most use cases
  • lg (large): Larger buttons for prominent actions or touch interfaces

Colors

Buttons inherit colors from the design system tokens. Available colors include:

  • primary (default): Brand primary color for main actions
  • secondary: Secondary brand color for supporting actions
  • success: Green color for positive or successful actions
  • info: Blue color for informational actions
  • warning: Amber/orange color for cautionary actions
  • error: Red color for destructive or error-related actions

States

Disabled

Disabled buttons prevent user interaction and indicate unavailable actions:

  • Do not respond to clicks or keyboard events
  • Display with reduced opacity
  • Show a "not-allowed" cursor on hover
  • Maintain accessibility with disabled attribute for screen readers

Loading

The loading state provides visual feedback during async operations:

  • Displays a circular progress indicator
  • Automatically disables the button to prevent multiple submissions
  • Works seamlessly with all variants and colors
  • Maintains button dimensions to prevent layout shift

Icon Buttons

Icon buttons are square buttons (48px × 48px) designed for icon-only actions. Use the :icon prop to enable icon button styling.

When to use:

  • Close/dismiss actions
  • Common actions (edit, delete, share, favorite)
  • Toolbar actions
  • Compact UI where space is limited
  • Actions where icons are universally understood

Important: Always provide an aria-label for screen readers when using icon-only buttons.

Icon Button Colors

Icon buttons work with all color options to convey semantic meaning.

Icon Button States

Icon buttons support disabled and loading states just like regular buttons.

Common Icon Button Patterns

Dialog Header with Close Button:

Dialog Title

Toolbar Actions:

Card Actions:

API Reference

Props

NameTypeDefaultDescription
variantStringelevatedButton style: 'elevated', 'flat', 'tonal', 'outlined', or 'text'
colorStringprimaryColor from design tokens (primary, secondary, error, warning, etc)
disabledBooleanfalseDisables button interaction
loadingBooleanfalseShows loading spinner and disables button
sizeStringmdButton size: 'sm', 'md', or 'lg'
iconBooleanfalseRenders button as icon-only with fixed 48px × 48px dimensions

Events

EventDescription
clickEmitted when button is clicked (if not disabled)

Slots

NameDescription
defaultButton label

Guidelines

Do

  • Use elevated buttons for primary, high-emphasis actions
  • Use outlined or text buttons for secondary actions
  • Provide clear, action-oriented button labels (e.g., "Save Changes", not just "Save")
  • Use icon buttons with aria-label for all icon-only buttons
  • Use loading state for async operations to provide feedback
  • Ensure adequate spacing between buttons in button groups

Don't

  • Use too many elevated buttons on one screen - reserve for primary actions
  • Use vague labels like "Click Here" or "Submit" without context
  • Create icon buttons without aria-label attributes
  • Use disabled state as the only indicator - provide helper text explaining why
  • Make buttons too small for touch targets (minimum 48×48px)
  • Use buttons for navigation - use links or router-links instead

Accessibility

The Button component is built with WCAG 2.1 AAA compliance in mind:

  • Keyboard Navigation: Fully accessible via Tab key, activated with Enter or Space
  • Focus States: Clear, high-contrast focus indicators
  • Semantic HTML: Uses native <button> elements for proper screen reader support
  • Color Contrast: All color variants meet AAA contrast requirements

Icon Button Accessibility

Icon-only buttons require special attention for screen reader users:

Always provide an aria-label:

vue
<!-- Good: Screen readers announce "Close dialog" -->
<ds-button icon aria-label="Close dialog">
  <v-icon icon="mdi-close" />
</ds-button>

<!-- Bad: Screen readers cannot identify the button's purpose -->
<ds-button icon>
  <v-icon icon="mdi-close" />
</ds-button>

Use descriptive labels that explain the action:

vue
<!-- Good: Clear, action-oriented -->
<ds-button icon aria-label="Delete user account">
  <v-icon icon="mdi-delete" />
</ds-button>

<!-- Less helpful: Too generic -->
<ds-button icon aria-label="Delete">
  <v-icon icon="mdi-delete" />
</ds-button>

Loading State Accessibility

When a button is in a loading state:

  • The button is automatically disabled
  • Screen readers announce the loading state
  • The loading spinner has appropriate ARIA attributes
vue
<ds-button :loading="isSubmitting" aria-label="Submit form">
  Submit
</ds-button>

Focus Management

  • Buttons receive keyboard focus with the Tab key
  • Focused buttons can be activated with Enter or Space
  • Focus order follows DOM order
  • Focus indicators meet WCAG AAA contrast requirements (3:1 minimum)

Usage Examples

Basic Usage

vue
<template>
  <ds-button @click="handleClick">Save Changes</ds-button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      console.log('Button clicked');
    },
  },
};
</script>
vue
<template>
  <ds-button @click="$router.push('/dashboard')">
    Go to Dashboard
  </ds-button>
</template>

Button Groups

vue
<template>
  <div class="d-flex gap-2">
    <ds-button variant="outlined">Cancel</ds-button>
    <ds-button>Save</ds-button>
  </div>
</template>

Built with Vue 3, Vuetify 3, and TypeScript