<script setup>
import { ref } from "vue";
import { Button } from "@dicehub/kappa/components/button";
const message = ref("No action yet");
</script>
<template>
<section class="run-panel">
<div><span>Rotor study · Run 042</span><strong>Ready to submit</strong></div>
<div class="actions">
<Button @click="message = 'Draft saved'">Save draft</Button>
<Button variant="primary" @click="message = 'Run submitted'">Run simulation</Button>
</div>
<output role="status" aria-live="polite">{{ message }}</output>
</section>
</template>Installation
Barrel
import { Button, LinkButton } from "@dicehub/kappa";Granular
import { Button, LinkButton } from "@dicehub/kappa/components/button";Usage
Use Button for actions and LinkButton for navigation. Button defaults to type="button", preventing accidental form submission.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
function saveCase() {
// Persist the current case.
}
</script>
<template>
<Button variant="primary" @click="saveCase">Save case</Button>
</template>Examples
Basic
The quiet secondary treatment is the default for dense technical workflows.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button>Save draft</Button>
</template>Variants
Choose emphasis from the action’s meaning and local hierarchy. A view should rarely need more than one primary action.
Primary
Highest-emphasis action in the local context.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="primary">Primary</Button>
</template>Secondary
Quiet default action for dense workflows.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="secondary">Secondary</Button>
</template>Outline
Neutral action on the surrounding surface.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="outline">Outline</Button>
</template>Ghost
Lowest-emphasis toolbar or contextual action.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="ghost">Ghost</Button>
</template>Destructive
Primary irreversible or dangerous action.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="destructive">Destructive</Button>
</template>Secondary Destructive
Quiet destructive action with red text.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="secondary-destructive">Secondary Destructive</Button>
</template>Destructive Outline
Outlined destructive compatibility treatment.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="destructive-outline">Destructive Outline</Button>
</template>Success
Explicit approval or successful transition.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="success">Success</Button>
</template>Warning
Action that needs caution before continuing.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="warning">Warning</Button>
</template>Link
Inline action styling; use LinkButton when it navigates.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button variant="link">Link</Button>
</template>Sizes
Use compact sizes in toolbars and data-dense controls; use base for standard forms.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button size="xs">Extra small</Button>
<Button size="sm">Small</Button>
<Button size="base">Base</Button>
<Button size="lg">Large</Button>
</template>With Icons
These examples use @lucide/vue, but icon accepts any Vue component. Set iconPosition with logical values so placement follows the reading direction.
pnpm add @lucide/vue<script setup>
import { ArrowRight, Plus } from "@lucide/vue";
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button :icon="Plus">New case</Button>
<Button :icon="ArrowRight" icon-position="inline-end" variant="outline">Export</Button>
</template>Icon-only
Use square or circle geometry and provide aria-label oraria-labelledby; the decorative icon is hidden from assistive technology.
<script setup>
import { Plus, RefreshCw } from "@lucide/vue";
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button :icon="Plus" shape="square" aria-label="Add case" />
<Button :icon="RefreshCw" shape="circle" variant="ghost" aria-label="Refresh runs" />
</template>Loading
Loading preserves the visible label, adds a spinner and aria-busy="true", and blocks duplicate activation.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button loading>Saving case</Button>
<Button variant="primary" loading>Submitting run</Button>
</template>Disabled
Disabled Button uses native disabled semantics. Disabled LinkButton renders a disabled native button so it cannot remain an apparently actionable anchor.
<script setup>
import { Button, LinkButton } from "@dicehub/kappa/components/button";
</script>
<template>
<Button disabled>Save case</Button>
<LinkButton href="/runs/042" disabled>Open run</LinkButton>
</template>Full Width
Use fullWidth for stacked mobile forms and narrow confirmation panels.
<script setup>
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<Button full-width variant="primary">Create project</Button>
</template>Links and asChild
LinkButton renders a real anchor. Use external for safe new-tab links andasChild to compose a router link without coupling Kappa to a router. The child owns its icon markup; when disabled, Kappa unwraps its label into a native disabled button.
<script setup>
import { RouterLink } from "vue-router";
import { LinkButton } from "@dicehub/kappa/components/button";
</script>
<template>
<LinkButton href="/runs">View runs</LinkButton>
<LinkButton href="https://dicehub.com" external>dicehub website</LinkButton>
<LinkButton as-child disabled>
<RouterLink to="/unavailable">Unavailable run</RouterLink>
</LinkButton>
<LinkButton as-child>
<RouterLink to="/projects">Open projects</RouterLink>
</LinkButton>
</template>Native Forms
Opt into native submit or reset behavior with the type prop.
<script setup>
import { ref } from "vue";
import { Button } from "@dicehub/kappa/components/button";
const message = ref("Ready");
</script>
<template>
<form aria-label="Case action form" @submit.prevent="message = 'Submitted'" @reset="message = 'Reset'">
<input name="case" value="Rotor study" />
<Button type="submit">Submit</Button>
<Button type="reset" variant="ghost">Reset</Button>
<output role="status" aria-live="polite">{{ message }}</output>
</form>
</template>Right-to-left
Logical icon positions preserve the intended leading and trailing relationships in RTL.
<script setup>
import { ArrowLeft, Plus } from "@lucide/vue";
import { Button } from "@dicehub/kappa/components/button";
</script>
<template>
<div dir="rtl">
<Button :icon="Plus">حالة جديدة</Button>
<Button :icon="ArrowLeft" icon-position="inline-end" variant="outline">تصدير</Button>
</div>
</template>Accessibility
- Use Button for actions and LinkButton for navigation; styling does not replace semantics.
- Icon-only controls need a concise accessible name describing the action.
- Loading retains its label, exposes
aria-busy, and prevents repeated activation. - Do not use only color to distinguish destructive, warning, success, or disabled actions.
- Keep visible focus indicators. Native buttons activate with Enter and Space; links activate with Enter.
- A title supplements a concise label; it is not a replacement for an accessible name.
API Reference
Button
Renders a native button and forwards native attributes, ARIA properties, classes, and listeners.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | ButtonVariant | "secondary" | Visual and semantic treatment. |
size | "xs" | "sm" | "base" | "lg" | "base" | Control height, spacing, and icon scale. |
shape | "base" | "square" | "circle" | "base" | Standard text control or icon-only geometry. |
type | "button" | "submit" | "reset" | "button" | Native button behavior, including form submission and reset. |
loading | boolean | false | Shows a spinner, sets aria-busy, and prevents activation. |
disabled | boolean | false | Disables native activation and focus. |
fullWidth | boolean | false | Fills the available inline size. |
icon | Component | — | Decorative icon rendered beside the label. |
iconProps | Record<string, unknown> | — | Attributes forwarded to the icon component. |
iconPosition | "inline-start" | "inline-end" | "inline-start" | Logical icon placement that follows text direction. |
title | string | number | — | Native advisory text; not a replacement for an accessible name. |
LinkButton
Renders an anchor when enabled, a disabled button when unavailable, or merges onto one semantic child when composed.
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | undefined | — | Native anchor destination; omit only when asChild supplies navigation. |
external | boolean | false | Opens in a new tab with a safe rel value. |
disabled | boolean | false | Renders a disabled native button so navigation and activation are unavailable. |
asChild | boolean | false | Merges styling and attributes onto one child link, such as RouterLink. |
icon | Component | — | Decorates native links. With asChild, render the icon inside the child instead. |
iconProps | Record<string, unknown> | — | Attributes forwarded to the native-link icon component. |
iconPosition | "inline-start" | "inline-end" | "inline-start" | Logical native-link icon placement. |
title | string | number | — | Native advisory text; not a replacement for an accessible name. |
variant / size / shape / fullWidth | Button styling props | shared defaults | Shares Button geometry and visual variants. |
Variant Reference
| Variant | Purpose |
|---|---|
primary | Highest-emphasis action in the local context. |
secondary | Quiet default action for dense workflows. |
outline | Neutral action on the surrounding surface. |
ghost | Lowest-emphasis toolbar or contextual action. |
destructive | Primary irreversible or dangerous action. |
secondary-destructive | Quiet destructive action with red text. |
destructive-outline | Outlined destructive compatibility treatment. |
success | Explicit approval or successful transition. |
warning | Action that needs caution before continuing. |
link | Inline action styling; use LinkButton when it navigates. |
Exports
| Export | Description |
|---|---|
Button | Native action button with complete visual and async states. |
LinkButton | Anchor and router-link composition with Button styling. |
BUTTON_VARIANTS / BUTTON_SIZES / BUTTON_SHAPES | Readonly visual option lists. |
BUTTON_ICON_POSITIONS / BUTTON_TYPES | Readonly logical icon-position and native-type lists. |
BUTTON_DEFAULT_* | Public variant, size, shape, icon-position, and type defaults. |
isButton* | Runtime guards for every public option union. |
resolveButton* | Runtime default resolvers for every public option union. |
ButtonProps / ButtonSlots / LinkButtonProps / LinkButtonSlots | Public Vue contracts. |
ButtonVisualProps | Visual props shared by Button and LinkButton. |
ButtonVariant / ButtonSize / ButtonShape / ButtonIconPosition / ButtonType | Public option unions. |