<script setup>
import { Toggle } from "@dicehub/kappa/components/toggle";
import { Bookmark } from "@lucide/vue";
</script>
<template>
<Toggle
aria-label="Toggle bookmark"
class="bookmark-toggle"
size="sm"
variant="outline"
>
<Bookmark aria-hidden="true" class="bookmark-toggle__icon" />
Bookmark
</Toggle>
</template>
<style scoped>
.bookmark-toggle[data-state="on"] .bookmark-toggle__icon {
fill: currentColor;
}
</style>Installation
Toggle is part of the main Kappa package. It uses a native pressed button and adds no state-machine dependency.
Barrel
import { Toggle } from "@dicehub/kappa";Granular
import { Toggle } from "@dicehub/kappa/components/toggle";Usage
Use Toggle for a persistent pressed state, such as bold text or a saved view. Use Button for a one-time action and Switch for a setting that takes effect immediately.
<script setup>
import { Bold } from "@lucide/vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
</script>
<template>
<Toggle aria-label="Bold" default-pressed>
<Bold aria-hidden="true" />
</Toggle>
</template>Composition
Toggle <button aria-pressed>
└── icon and/or visible labelKappa renders a native button with aria-pressed. The browser owns focus and keyboard activation. Kappa owns controlled and uncontrolled state, compact geometry, and the visible on and off states.
The API uses a native button with aria-pressed. Ark UI provides Toggle Group, but it does not provide a standalone Toggle primitive. Wrapping one group item would add an unnecessary element and group keyboard behavior, so Kappa uses the native button pattern.
Kappa uses the size name base to match the rest of the library. Its Vue event ispressedChange, which corresponds to Base UI's ReactonPressedChange callback.
Examples
Variants
Use the default treatment in quiet toolbars. Use outline when the control needs a visible boundary.
<script setup>
import { Bold, Italic } from "@lucide/vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
</script>
<template>
<Toggle aria-label="Bold" default-pressed>
<Bold aria-hidden="true" />
</Toggle>
<Toggle aria-label="Italic" variant="outline">
<Italic aria-hidden="true" />
</Toggle>
</template>With Text
Keep a visible label when the icon alone may not be clear.
<script setup>
import { Italic } from "@lucide/vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
</script>
<template>
<Toggle variant="outline">
<Italic aria-hidden="true" />
Italic
</Toggle>
</template>Sizes
Small, base, and large sizes keep one pressed-state contract.
<script setup>
import { Bookmark } from "@lucide/vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
</script>
<template>
<Toggle size="sm" variant="outline">
<Bookmark aria-hidden="true" />
Small
</Toggle>
<Toggle size="base" variant="outline">
<Bookmark aria-hidden="true" />
Base
</Toggle>
<Toggle size="lg" variant="outline">
<Bookmark aria-hidden="true" />
Large
</Toggle>
</template>Controlled
Use v-model:pressed when application state must own and report the value.
<script setup>
import { Bookmark } from "@lucide/vue";
import { ref } from "vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
const saved = ref(true);
</script>
<template>
<Toggle v-model:pressed="saved" aria-label="Save report" variant="outline">
<Bookmark :fill="saved ? 'currentColor' : 'none'" aria-hidden="true" />
</Toggle>
<output aria-live="polite">{{ saved ? "Saved" : "Not saved" }}</output>
</template>Disabled
A disabled toggle preserves its visible state and blocks focus and activation.
<script setup>
import { Bold, Italic } from "@lucide/vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
</script>
<template>
<Toggle disabled aria-label="Bold unavailable">
<Bold aria-hidden="true" />
</Toggle>
<Toggle disabled default-pressed aria-label="Italic enabled and unavailable">
<Italic aria-hidden="true" />
</Toggle>
</template>Right to Left
Logical spacing keeps icon and text order correct in right-to-left content.
<script setup>
import { Bookmark } from "@lucide/vue";
import { Toggle } from "@dicehub/kappa/components/toggle";
</script>
<template>
<div dir="rtl" lang="ar">
<Toggle class="bookmark-toggle" variant="outline">
<Bookmark aria-hidden="true" class="bookmark-toggle__icon" />
حفظ
</Toggle>
</div>
</template>
<style scoped>
.bookmark-toggle[data-state="on"] .bookmark-toggle__icon {
fill: currentColor;
}
</style>Accessibility
- The native button keeps standard focus, Space, Enter, and disabled behavior.
aria-pressedexposes the resolved on or off state.- Give icon-only toggles an
aria-labeloraria-labelledby. - Use a visible text label when an icon may be unfamiliar.
- The default
type=buttonprevents accidental form submission. - Pressed, disabled, focus-visible, forced-colors, and reduced-motion states remain distinct.
Keyboard Support
| Key | Behavior |
|---|---|
Space | Toggles the focused button. |
Enter | Toggles the focused button. |
API Reference
Toggle
Renders a native pressed button. Native attributes, data attributes, event listeners, and consumer classes pass to the root.
| Prop | Type | Default | Description |
|---|---|---|---|
pressed | boolean | — | Controls the pressed state. Use with v-model:pressed. |
defaultPressed | boolean | false | Sets the initial state when the component is uncontrolled. |
variant | "default" | "outline" | "default" | Selects the quiet or bordered visual treatment. |
size | "sm" | "base" | "lg" | "base" | Selects compact control, icon, spacing, and text geometry. |
disabled | boolean | false | Blocks focus and state changes with native button behavior. |
type | "button" | "submit" | "reset" | "button" | Sets the native button type. The safe default prevents accidental form submission. |
Events
| Event | Payload | Description |
|---|---|---|
update:pressed | boolean | Supports v-model:pressed and controlled state. |
pressedChange | boolean | Reports the requested pressed state after activation. |
Slots
| Slot | Description |
|---|---|
default | Renders an icon, visible label, or both inside the button. |
Data Attributes
| Attribute | Value | Description |
|---|---|---|
data-slot | "toggle" | Identifies the root button. |
data-state | "on" | "off" | Exposes the resolved pressed state. |
data-pressed | present | Appears while the toggle is pressed. |
data-disabled | present | Appears while the native button is disabled. |
data-variant | "default" | "outline" | Exposes the resolved visual treatment. |
data-size | "sm" | "base" | "lg" | Exposes the resolved compact size. |
Exports
| Export | Description |
|---|---|
Toggle | Native two-state pressed button. |
ToggleProps / ToggleEmits / ToggleSlots | Public Vue component, event, and slot contracts. |
ToggleVariant / ToggleSize / ToggleType | Supported visual, size, and native button options. |
TOGGLE_VARIANTS / TOGGLE_SIZES / TOGGLE_TYPES | Runtime option lists and safe defaults. |
TOGGLE_DEFAULT_VARIANT / TOGGLE_DEFAULT_SIZE / TOGGLE_DEFAULT_TYPE | Published defaults for visual, size, and native button options. |
isToggle* / resolveToggle* | Runtime guards and safe option resolvers. |