diff --git a/.changeset/switch.md b/.changeset/switch.md
new file mode 100644
index 0000000..2f452dd
--- /dev/null
+++ b/.changeset/switch.md
@@ -0,0 +1,23 @@
+---
+'@dunky.dev/switch': minor
+'@dunky.dev/react-switch': minor
+---
+
+Add the Switch primitive — a binary on/off control following the WAI-ARIA APG
+pattern, shipped as an agnostic core (`@dunky.dev/switch`) plus a React binding
+(`@dunky.dev/react-switch`).
+
+```tsx
+import { Switch } from '@dunky.dev/react-switch'
+
+function App() {
+ return (
+
+
+
+
+ Airplane mode
+
+ )
+}
+```
diff --git a/packages/core/switch/README.md b/packages/core/switch/README.md
new file mode 100644
index 0000000..6a5d3a3
--- /dev/null
+++ b/packages/core/switch/README.md
@@ -0,0 +1,27 @@
+# @dunky.dev/switch
+
+The framework-agnostic switch interaction, modeled as a state machine on
+`@dunky.dev/state-machine`. Pure logic — no substrate, no framework. Consumers
+pair it with a substrate driver rather than driving the machine directly.
+
+The behavior contract — scenarios, guarantees, driver obligations — lives in
+[SPEC.md](./SPEC.md).
+
+## Install
+
+```sh
+npm install @dunky.dev/switch
+```
+
+## Usage
+
+```ts
+import { machine, connector } from '@dunky.dev/state-machine'
+import { switchMachine, switchConnect } from '@dunky.dev/switch'
+
+// `id` is substrate-minted (SSR-safe); the connect derives the per-part ids.
+const service = machine(switchMachine({ ...options, id: 'my-switch' }))
+connector(service, switchConnect, options) // wires the consumer callbacks
+service.start()
+service.send({ type: 'toggle' })
+```
diff --git a/packages/core/switch/SPEC.md b/packages/core/switch/SPEC.md
new file mode 100644
index 0000000..6251e62
--- /dev/null
+++ b/packages/core/switch/SPEC.md
@@ -0,0 +1,111 @@
+# SPEC / Switch
+
+## Reference
+
+- **W3C pattern**: [APG Switch](https://www.w3.org/WAI/ARIA/apg/patterns/switch/),
+ over the normative
+ [WAI-ARIA 1.2 `switch`](https://www.w3.org/TR/wai-aria-1.2/#switch) role
+ definition.
+- **State machine**: built on `@dunky.dev/state-machine`.
+- **Prior art**: API shape modeled on the Radix, Base UI, and Ark switches.
+
+## Overview
+
+A switch is a binary control that turns a setting on or off, taking effect
+immediately — airplane mode, notifications, dark theme. Unlike a checkbox it
+never collects a choice for later submission and never has a mixed state: it
+is always exactly on or off.
+
+## Anatomy
+
+```
+ — root; owns checked state, renders nothing of its own
+ |_ — the interactive element: carries the switch role and checked state
+ | |_ — the knob; purely visual, styled off data-state
+ |_