diff --git a/playground-vue/src/app.vue b/playground-vue/src/app.vue
index cc2e69d572..52bd4e74d6 100644
--- a/playground-vue/src/app.vue
+++ b/playground-vue/src/app.vue
@@ -64,6 +64,7 @@ const components = [
'textarea',
'timeline',
'toast',
+ 'toggle',
'tooltip',
'tree'
]
diff --git a/playground/app/app.vue b/playground/app/app.vue
index 7348fbd70f..ed569d4eb0 100644
--- a/playground/app/app.vue
+++ b/playground/app/app.vue
@@ -64,6 +64,7 @@ const components = [
'textarea',
'timeline',
'toast',
+ 'toggle',
'tooltip',
'tree'
]
diff --git a/playground/app/pages/components/toggle.vue b/playground/app/pages/components/toggle.vue
new file mode 100644
index 0000000000..11b77de156
--- /dev/null
+++ b/playground/app/pages/components/toggle.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/runtime/components/Toggle.vue b/src/runtime/components/Toggle.vue
new file mode 100644
index 0000000000..36956deefa
--- /dev/null
+++ b/src/runtime/components/Toggle.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/runtime/types/index.ts b/src/runtime/types/index.ts
index f413b71caa..d5b9c5a826 100644
--- a/src/runtime/types/index.ts
+++ b/src/runtime/types/index.ts
@@ -50,6 +50,7 @@ export * from '../components/Textarea.vue'
export * from '../components/Timeline.vue'
export * from '../components/Toast.vue'
export * from '../components/Toaster.vue'
+export * from '../components/Toggle.vue'
export * from '../components/Tooltip.vue'
export * from '../components/Tree.vue'
export * from './form'
diff --git a/test/components/Toggle.spec.ts b/test/components/Toggle.spec.ts
new file mode 100644
index 0000000000..4cb636e760
--- /dev/null
+++ b/test/components/Toggle.spec.ts
@@ -0,0 +1,29 @@
+import { describe, it, expect } from 'vitest'
+import Toggle from '../../src/runtime/components/Toggle.vue'
+import type { ToggleProps } from '../../src/runtime/components/Toggle.vue'
+import ComponentRender from '../component-render'
+import theme from '#build/ui/button'
+
+describe('Toggle', () => {
+ const sizes = Object.keys(theme.variants.size) as any
+ const variants = Object.keys(theme.variants.variant) as any
+ const colors = Object.keys(theme.variants.color) as any
+
+ it.each([
+ // Props
+ ['with label', { props: { label: 'Toggle' } }],
+ ...sizes.map((size: string) => [`with size ${size}`, { props: { label: 'Toggle', size } }]),
+ ...variants.map((variant: string) => [`with primary variant ${variant}`, { props: { label: 'Toggle', variant } }]),
+ ...colors.map((color: string) => [`with neutral color ${color}`, { props: { label: 'Toggle', color } }]),
+ ['with icon', { props: { icon: 'i-lucide-rocket' } }],
+ ['with leading and icon', { props: { leading: true, icon: 'i-lucide-arrow-left' } }],
+ ['with leadingIcon', { props: { leadingIcon: 'i-lucide-arrow-left' } }],
+ ['with trailing and icon', { props: { trailing: true, icon: 'i-lucide-arrow-right' } }],
+ ['with trailingIcon', { props: { trailingIcon: 'i-lucide-arrow-right' } }],
+ ['with class', { props: { label: 'Toggle', class: 'rounded-none' } }],
+ ['with ui', { props: { label: 'Toggle', ui: { base: 'rounded-none' } } }]
+ ])('renders %s correctly', async (nameOrHtml: string, options: { props?: ToggleProps }) => {
+ const html = await ComponentRender(nameOrHtml, options, Toggle)
+ expect(html).toMatchSnapshot()
+ })
+})
diff --git a/test/components/__snapshots__/Toggle-vue.spec.ts.snap b/test/components/__snapshots__/Toggle-vue.spec.ts.snap
new file mode 100644
index 0000000000..8db569ea60
--- /dev/null
+++ b/test/components/__snapshots__/Toggle-vue.spec.ts.snap
@@ -0,0 +1,206 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Toggle > renders with class correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with icon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with label correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with leading and icon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with leadingIcon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color error correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color info correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color neutral correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color primary correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color secondary correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color success correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color warning correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant ghost correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant link correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant outline correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant soft correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant solid correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant subtle correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size lg correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size md correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size sm correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size xl correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size xs correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with trailing and icon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with trailingIcon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with ui correctly 1`] = `
+"
+"
+`;
diff --git a/test/components/__snapshots__/Toggle.spec.ts.snap b/test/components/__snapshots__/Toggle.spec.ts.snap
new file mode 100644
index 0000000000..77e1a6764c
--- /dev/null
+++ b/test/components/__snapshots__/Toggle.spec.ts.snap
@@ -0,0 +1,203 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Toggle > renders with class correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with icon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with label correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with leading and icon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with leadingIcon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color error correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color info correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color neutral correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color primary correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color secondary correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color success correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with neutral color warning correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant ghost correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant link correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant outline correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant soft correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant solid correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with primary variant subtle correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size lg correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size md correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size sm correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size xl correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with size xs correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with trailing and icon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with trailingIcon correctly 1`] = `
+"
+"
+`;
+
+exports[`Toggle > renders with ui correctly 1`] = `
+"
+"
+`;