Are you an LLM? You can read better optimized documentation at /components/button.md for this page in Markdown format
Button
Buttons trigger actions and communicate what will happen when pressed.
ts
import { CoarButton } from '@cocoar/vue-ui';Variants
Choose the appropriate variant based on the action's importance and context.
vue
<template>
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
<CoarButton variant="primary">Primary</CoarButton>
<CoarButton variant="secondary">Secondary</CoarButton>
<CoarButton variant="tertiary">Tertiary</CoarButton>
<CoarButton variant="danger">Danger</CoarButton>
<CoarButton variant="ghost">Ghost</CoarButton>
</div>
</template>
<script setup lang="ts">
import { CoarButton } from '@cocoar/vue-ui';
</script>
When to use each variant:
- Primary — Main call-to-action. Use sparingly, typically once per view.
- Secondary — Alternative actions. Pairs well with primary buttons.
- Tertiary — Low-emphasis actions with brand color hint.
- Danger — Destructive actions like delete or remove.
- Ghost — Minimal emphasis, often for cancel or dismiss.
Sizes
Four sizes to fit different contexts and layouts.
xs 27px | s 32px | m 40px | l 48px
vue
<template>
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end;">
<CoarButton size="xs">Extra Small</CoarButton>
<CoarButton size="s">Small</CoarButton>
<CoarButton size="m">Medium</CoarButton>
<CoarButton size="l">Large</CoarButton>
</div>
<p style="margin-top: 8px; font-size: 13px; color: #64748b;">
<code>xs</code> 27px | <code>s</code> 32px | <code>m</code> 40px | <code>l</code> 48px
</p>
</template>
<script setup lang="ts">
import { CoarButton } from '@cocoar/vue-ui';
</script>
Icons
Add icons before or after the label to enhance meaning.
vue
<template>
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
<CoarButton icon-start="plus">Add Item</CoarButton>
<CoarButton variant="secondary" icon-end="chevron-right">Next</CoarButton>
<CoarButton variant="tertiary" icon-start="clipboard">Download</CoarButton>
<CoarButton variant="danger" icon-start="trash-2">Delete</CoarButton>
</div>
</template>
<script setup lang="ts">
import { CoarButton } from '@cocoar/vue-ui';
</script>
Loading State
Show a spinner while an async action is in progress. Click to test.
With start icon:
Icon end:
vue
<template>
<div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: center;">
<div style="display: flex; align-items: center; gap: 8px;">
<span style="font-size: 13px; color: #64748b; min-width: 100px;">With start icon:</span>
<CoarButton icon-start="check" :loading="isLoading" @click="simulateLoading">Save Changes</CoarButton>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<span style="font-size: 13px; color: #64748b; min-width: 100px;">Icon end:</span>
<CoarButton icon-end="chevron-right" :loading="isLoadingEnd" @click="simulateLoadingEnd">Continue</CoarButton>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { CoarButton } from '@cocoar/vue-ui';
const isLoading = ref(false);
const isLoadingEnd = ref(false);
function simulateLoading() {
isLoading.value = true;
setTimeout(() => { isLoading.value = false; }, 2000);
}
function simulateLoadingEnd() {
isLoadingEnd.value = true;
setTimeout(() => { isLoadingEnd.value = false; }, 2000);
}
</script>
Disabled State
Disable buttons when actions are not available.
vue
<template>
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
<CoarButton :disabled="true">Primary</CoarButton>
<CoarButton variant="secondary" :disabled="true">Secondary</CoarButton>
<CoarButton variant="tertiary" :disabled="true">Tertiary</CoarButton>
<CoarButton variant="danger" :disabled="true">Danger</CoarButton>
<CoarButton variant="ghost" :disabled="true">Ghost</CoarButton>
</div>
</template>
<script setup lang="ts">
import { CoarButton } from '@cocoar/vue-ui';
</script>
Full Width
Buttons can expand to fill their container.
vue
<template>
<div style="max-width: 360px; display: flex; flex-direction: column; gap: 8px;">
<CoarButton :full-width="true">Full Width Primary</CoarButton>
<CoarButton variant="secondary" :full-width="true">Full Width Secondary</CoarButton>
</div>
</template>
<script setup lang="ts">
import { CoarButton } from '@cocoar/vue-ui';
</script>
Accessibility
Keyboard Navigation
| Key | Action |
|---|---|
Tab | Move focus to button |
Shift + Tab | Move focus backward |
Enter | Activate button |
Space | Activate button |
INFO
Disabled and loading buttons cannot be activated via keyboard.
Screen Reader Support
- Button text or
aria-labelannounces on focus - Disabled state properly communicated
- Loading state indicates button is busy
- Icon-only buttons should include
aria-label typeattribute ensures correct form behavior
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'tertiary' | 'danger' | 'ghost' | 'primary' | Button style variant |
size | 'xs' | 's' | 'm' | 'l' | 'm' | Button size |
iconStart | string | undefined | Icon name before label |
iconEnd | string | undefined | Icon name after label |
loading | boolean | false | Show loading spinner |
disabled | boolean | false | Disable the button |
fullWidth | boolean | false | Expand to fill container |
type | 'button' | 'submit' | 'reset' | 'button' | HTML button type |
Events
| Event | Payload | Description |
|---|---|---|
click | MouseEvent | Emitted when clicked (not when disabled/loading) |
i18n Keys
These keys can be translated via @cocoar/vue-localization.
| Key | Default (English) | Used as |
|---|---|---|
coar.ui.button.loading | 'Loading' | Screen reader announcement when loading is true |