Skip to content
Kappa
Switch
@dicehub/kappav0.4.2

Switch

A binary form control for settings that take effect immediately.

<script setup>
import { ref } from "vue";
import { Switch } from "@dicehub/kappa/components/switch";

const airplaneMode = ref(false);
</script>

<template>
  <Switch.Root v-model:checked="airplaneMode">
    <Switch.Control />
    <Switch.Label>Airplane mode</Switch.Label>
  </Switch.Root>
</template>

Installation

Switch is part of the main Kappa package and uses the Ark UI Vue switch primitive.

Barrel

import {
  Switch,
  SwitchRoot,
  SwitchRootProvider,
  SwitchControl,
  SwitchThumb,
  SwitchLabel,
  SwitchContext,
} from "@dicehub/kappa";

Granular

import {
  Switch,
  SwitchRoot,
  SwitchRootProvider,
  SwitchControl,
  SwitchThumb,
  SwitchLabel,
  SwitchContext,
} from "@dicehub/kappa/components/switch";

Usage

Use Switch for a setting that changes immediately. Use Checkbox when the user confirms a selection later with a form action. Root renders the native hidden input automatically.

<script setup>
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <Switch.Root default-checked name="automatic-updates" value="enabled">
    <Switch.Control />
    <Switch.Label>Automatic updates</Switch.Label>
  </Switch.Root>
</template>

Composition

Typical part hierarchy
Switch.Root
├── Switch.Control
│   └── Switch.Thumb
├── Switch.Label
└── HiddenInput (automatic)

Ark UI Switch owns binary state, keyboard behavior, focus, label activation, and the form input. Kappa adds the compound exports, automatic hidden input, default thumb, three compact sizes, and semantic styling.

Kappa uses Ark parts and native fieldsets instead of a custom switch-group state layer.

<script setup>
import {
  SwitchRoot,
  SwitchControl,
  SwitchThumb,
  SwitchLabel,
} from "@dicehub/kappa/components/switch";
</script>

<template>
  <SwitchRoot>
    <SwitchControl>
      <SwitchThumb />
    </SwitchControl>
    <SwitchLabel>Automatic updates</SwitchLabel>
  </SwitchRoot>
</template>

Examples

With Description

Put persistent guidance beside the switch when the setting needs more context.

<script setup>
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <Switch.Root class="setting" default-checked>
    <Switch.Label class="setting__copy">
      <span class="setting__title">Share across devices</span>
      <span class="setting__description">
        Keep preferences synchronized on signed-in devices.
      </span>
    </Switch.Label>
    <Switch.Control />
  </Switch.Root>
</template>

<style scoped>
.setting {
  width: 100%;
  justify-content: space-between;
  align-items: flex-start;
}

.setting__copy {
  display: grid;
  gap: 0.125rem;
}

.setting__title {
  font-weight: 600;
}

.setting__description {
  color: var(--kappa-subtle, #6c7480);
  font-size: 0.75rem;
  font-weight: 400;
}
</style>

Choice Card

Because Root renders a label, the complete bordered row remains one clickable target.

<script setup>
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <Switch.Root class="choice-card" default-checked>
    <Switch.Label class="choice-card__copy">
      <span class="choice-card__title">Enable notifications</span>
      <span class="choice-card__description">
        Receive a message when important activity needs attention.
      </span>
    </Switch.Label>
    <Switch.Control />
  </Switch.Root>
</template>

<style scoped>
.choice-card {
  width: 100%;
  align-items: flex-start;
  justify-content: space-between;
  padding: 0.875rem;
  border: 1px solid var(--kappa-line, #e3e6eb);
  border-radius: 0.625rem;
}

.choice-card:has([data-state="checked"]) {
  border-color: var(--kappa-accent, #4356e8);
}

.choice-card__copy {
  display: grid;
  gap: 0.25rem;
}

.choice-card__title {
  font-weight: 600;
}

.choice-card__description {
  color: var(--kappa-subtle, #6c7480);
  font-size: 0.75rem;
  font-weight: 400;
}
</style>

Controlled

Use v-model:checked when application state must own and report the value.

State: on
<script setup>
import { ref } from "vue";
import { Switch } from "@dicehub/kappa/components/switch";

const focusMode = ref(true);
</script>

<template>
  <Switch.Root v-model:checked="focusMode">
    <Switch.Control />
    <Switch.Label>Focus mode</Switch.Label>
  </Switch.Root>
  <output aria-live="polite">State: {{ focusMode ? "on" : "off" }}</output>
</template>

State from Context

Read the current state inside the component without creating a second source of truth.

<script setup>
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <Switch.Root default-checked>
    <Switch.Control />
    <Switch.Label>
      Wi-Fi
      <Switch.Context v-slot="{ checked }">
        <span>{{ checked ? "On" : "Off" }}</span>
      </Switch.Context>
    </Switch.Label>
  </Switch.Root>
</template>

States

Disabled, read-only, and invalid states keep distinct behavior and visible treatment.

You must accept the terms to continue.
<script setup>
import { Field } from "@dicehub/kappa/components/field";
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <Switch.Root disabled>
    <Switch.Control />
    <Switch.Label>Disabled</Switch.Label>
  </Switch.Root>

  <Switch.Root disabled default-checked>
    <Switch.Control />
    <Switch.Label>Disabled and on</Switch.Label>
  </Switch.Root>

  <Switch.Root read-only default-checked>
    <Switch.Control />
    <Switch.Label>Read-only</Switch.Label>
  </Switch.Root>

  <Field.Root id="terms" invalid>
    <Switch.Root invalid required>
      <Switch.Control />
      <Switch.Label>Accept the terms</Switch.Label>
    </Switch.Root>
    <Field.ErrorText>You must accept the terms to continue.</Field.ErrorText>
  </Field.Root>
</template>

Sizes

Use small, base, or large geometry without changing the interaction contract.

<script setup>
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <Switch.Root size="sm" default-checked>
    <Switch.Control />
    <Switch.Label>Small</Switch.Label>
  </Switch.Root>
  <Switch.Root size="base" default-checked>
    <Switch.Control />
    <Switch.Label>Base</Switch.Label>
  </Switch.Root>
  <Switch.Root size="lg" default-checked>
    <Switch.Control />
    <Switch.Label>Large</Switch.Label>
  </Switch.Root>
</template>

Native Form

The automatic hidden input submits name and value through native FormData.

Submit the form to inspect its value.
<script setup>
import { ref } from "vue";
import { Button } from "@dicehub/kappa/components/button";
import { Switch } from "@dicehub/kappa/components/switch";

const result = ref("Submit the form to inspect its value.");
const handleSubmit = (event) => {
  const data = new FormData(event.currentTarget);
  result.value = data.has("product-updates")
    ? "Product updates enabled"
    : "Product updates disabled";
};
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <Switch.Root name="product-updates" value="enabled" default-checked>
      <Switch.Control />
      <Switch.Label>Product updates</Switch.Label>
    </Switch.Root>
    <Button type="submit">Save preferences</Button>
    <output aria-live="polite">{{ result }}</output>
  </form>
</template>

Right to Left

Logical thumb positioning mirrors the checked state in right-to-left layouts.

<script setup>
import { Switch } from "@dicehub/kappa/components/switch";
</script>

<template>
  <div dir="rtl" lang="ar">
    <Switch.Root dir="rtl" default-checked>
      <Switch.Control />
      <Switch.Label>تفعيل الإشعارات</Switch.Label>
    </Switch.Root>
  </div>
</template>

Accessibility

  • Every switch needs a visible Switch.Label or an equivalent accessible name.
  • The hidden checkbox input preserves native focus, form submission, reset, and validation behavior.
  • Use Switch only for immediate binary settings. Use Checkbox for agreement or batch selection.
  • Pair invalid state with clear error text. Field supplies the hidden input’s aria-errormessage.
  • Do not use “on” and “off” as the label. Name the setting that changes.
  • Keep checked and unchecked meaning stable. Do not reverse the label after activation.
  • Motion follows reduced-motion preferences, and forced-colors mode keeps track geometry visible.

Keyboard Support

KeyAction
SpaceToggles the focused switch.

API Reference

Switch.Root

PropTypeDefaultDescription
checkedboolean—Controls the checked state.
defaultCheckedbooleanfalseSets the initial uncontrolled state.
size"sm" | "base" | "lg""base"Selects compact track, thumb, gap, and type geometry.
dir"ltr" | "rtl"inherited Ark localeOverrides the locale direction used by Ark UI and logical thumb movement.
disabledbooleanfalseBlocks focus and state changes.
readOnlybooleanfalseKeeps the value available but blocks changes.
invalidbooleanfalseMarks the control invalid and applies the danger treatment.
requiredbooleanfalseMarks the hidden native input as required.
name / value / formstring—Configures native form submission and external form association.
id / idsstring / objectgeneratedSets the machine or individual part identifiers.
labelstring—Supplies the localized accessible state label used by Ark UI.
asChildbooleanfalseMerges root behavior onto one direct label child.

Parts

PartElementDescription
Switch.RootlabelOwns state, interaction, size, and the automatic hidden input.
Switch.ControlspanRenders the focusable visual track and a default Thumb.
Switch.ThumbspanMoves between logical inline edges as state changes.
Switch.LabelspanNames the switch and expands the clickable target.
Switch.Context—Exposes checked, disabled, focused, setChecked, and toggleChecked.
Switch.RootProviderlabelUses a machine returned by useSwitch instead of creating one.

Events

EventPayloadDescription
update:checkedbooleanSupports v-model:checked and controlled state.
checkedChangeSwitchCheckedChangeDetailsReports the complete Ark state-change details.

Data Attributes

AttributeValueDescription
data-state"checked" | "unchecked"Exposes the current binary state on Ark parts.
data-size"sm" | "base" | "lg"Exposes the resolved Kappa size on Root.
data-focus-visiblepresentMarks keyboard-visible focus on Control.
data-hover / data-activepresentMarks pointer hover and active press states.
data-disabled / data-readonlypresentMarks non-editable states.
data-invalid / data-requiredpresentMarks form-validation states.

Exports

ExportDescription
SwitchCompound root with Root, RootProvider, Control, Thumb, Label, and Context.
SwitchRoot / SwitchRootProviderNamed machine-owning and externally provided roots.
SwitchControl / SwitchThumb / SwitchLabel / SwitchContextNamed composition parts.
SwitchProps / SwitchEmits / SwitchSize / SwitchDirectionPublic Vue, size, and direction contracts.
SWITCH_SIZES / SWITCH_DEFAULT_SIZESupported compact sizes and default.
isSwitchSize / resolveSwitchSizeSize guard and safe resolver.
switchAnatomy / useSwitch / useSwitchContextRe-exported Ark UI anatomy and hooks.