diff --git a/examples/checkbox-example/.eslintrc.js b/examples/checkbox-example/.eslintrc.js
new file mode 100644
index 00000000..8430608b
--- /dev/null
+++ b/examples/checkbox-example/.eslintrc.js
@@ -0,0 +1,12 @@
+module.exports = {
+ "root": true,
+ "extends": [
+ "lxsmnsyc/typescript/react"
+ ],
+ "parserOptions": {
+ "project": "./tsconfig.eslint.json",
+ "tsconfigRootDir": __dirname,
+ },
+ "rules": {
+ }
+};
diff --git a/examples/checkbox-example/.gitignore b/examples/checkbox-example/.gitignore
new file mode 100644
index 00000000..53f7466a
--- /dev/null
+++ b/examples/checkbox-example/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+*.local
\ No newline at end of file
diff --git a/examples/checkbox-example/favicon.svg b/examples/checkbox-example/favicon.svg
new file mode 100644
index 00000000..de4aeddc
--- /dev/null
+++ b/examples/checkbox-example/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/examples/checkbox-example/index.html b/examples/checkbox-example/index.html
new file mode 100644
index 00000000..78ed111d
--- /dev/null
+++ b/examples/checkbox-example/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite App
+
+
+
+
+
+
diff --git a/examples/checkbox-example/package.json b/examples/checkbox-example/package.json
new file mode 100644
index 00000000..cc75b585
--- /dev/null
+++ b/examples/checkbox-example/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "checkbox-example",
+ "version": "0.6.4",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "serve": "vite preview"
+ },
+ "devDependencies": {
+ "autoprefixer": "^10.2.6",
+ "babel-preset-solid": "^1.1.1",
+ "eslint": "^7.32.0",
+ "eslint-config-lxsmnsyc": "^0.2.3",
+ "postcss": "^8.3.5",
+ "typescript": "^4.3.2",
+ "vite": "^2.4.4",
+ "vite-plugin-solid": "^2.0.1"
+ },
+ "dependencies": {
+ "solid-headless": "0.6.4",
+ "solid-js": "^1.1.0",
+ "tailwindcss": "^2.2.4"
+ },
+ "private": true,
+ "publishConfig": {
+ "access": "restricted"
+ }
+}
diff --git a/examples/checkbox-example/postcss.config.js b/examples/checkbox-example/postcss.config.js
new file mode 100644
index 00000000..3a75af87
--- /dev/null
+++ b/examples/checkbox-example/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ }
+};
\ No newline at end of file
diff --git a/examples/checkbox-example/src/App.tsx b/examples/checkbox-example/src/App.tsx
new file mode 100644
index 00000000..29f0f3fd
--- /dev/null
+++ b/examples/checkbox-example/src/App.tsx
@@ -0,0 +1,113 @@
+import {
+ TailwindDialog,
+ TailwindDialogPanel,
+ TailwindDialogTitle,
+ TailwindTransition,
+ TailwindTransitionChild,
+ TailwindDialogOverlay,
+ TailwindCheckbox,
+ TailwindCheckboxIndicator,
+ TailwindCheckboxLabel,
+ TailwindCheckboxDescription,
+} from 'solid-headless';
+import { createSignal, JSX, Switch, Match } from 'solid-js';
+
+function CheckIcon(props: JSX.IntrinsicElements['svg']): JSX.Element {
+ return (
+
+ );
+}
+
+function CloseIcon(props: JSX.IntrinsicElements['svg']): JSX.Element {
+ return (
+
+ );
+}
+
+function UndefinedIcon(props: JSX.IntrinsicElements['svg']): JSX.Element {
+ return (
+
+ );
+}
+
+export default function App(): JSX.Element {
+ const [checked, setChecked] = createSignal();
+
+ return (
+ <>
+
+
+
+
+
+ Mixed
+
+
+
+ Checked
+
+
+
+ Unchecked
+
+
+
+
+
+
+ This is a checkbox label
+
+
+ This is a checkbox description
+
+
+
+
+ >
+ );
+}
diff --git a/examples/checkbox-example/src/main.tsx b/examples/checkbox-example/src/main.tsx
new file mode 100644
index 00000000..933e785e
--- /dev/null
+++ b/examples/checkbox-example/src/main.tsx
@@ -0,0 +1,20 @@
+import { render } from 'solid-js/web';
+import App from './App';
+
+import './style.css';
+
+function Root() {
+ return (
+
+ );
+}
+
+const app = document.getElementById('app');
+
+if (app) {
+ render(() => , app);
+}
diff --git a/examples/checkbox-example/src/style.css b/examples/checkbox-example/src/style.css
new file mode 100644
index 00000000..b5c61c95
--- /dev/null
+++ b/examples/checkbox-example/src/style.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/examples/checkbox-example/src/vite-env.d.ts b/examples/checkbox-example/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/examples/checkbox-example/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/checkbox-example/tailwind.config.js b/examples/checkbox-example/tailwind.config.js
new file mode 100644
index 00000000..4ff1450e
--- /dev/null
+++ b/examples/checkbox-example/tailwind.config.js
@@ -0,0 +1,19 @@
+const colors = require('tailwindcss/colors');
+
+module.exports = {
+ mode: 'jit',
+ purge: [
+ './src/**/*.tsx',
+ ],
+ darkMode: 'class', // or 'media' or 'class'
+ theme: {
+ extend: {
+ colors: {
+ ...colors,
+ },
+ },
+ },
+ variants: {},
+ plugins: [
+ ],
+};
\ No newline at end of file
diff --git a/examples/checkbox-example/tsconfig.eslint.json b/examples/checkbox-example/tsconfig.eslint.json
new file mode 100644
index 00000000..7b3b25a2
--- /dev/null
+++ b/examples/checkbox-example/tsconfig.eslint.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "lib": ["ESNext", "DOM"],
+ "moduleResolution": "Node",
+ "strict": true,
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "noEmit": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true,
+ "jsx": "preserve",
+ "jsxImportSource": "solid-js",
+ },
+ "include": ["./src"]
+}
diff --git a/examples/checkbox-example/tsconfig.json b/examples/checkbox-example/tsconfig.json
new file mode 100644
index 00000000..7b3b25a2
--- /dev/null
+++ b/examples/checkbox-example/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "lib": ["ESNext", "DOM"],
+ "moduleResolution": "Node",
+ "strict": true,
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "noEmit": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true,
+ "jsx": "preserve",
+ "jsxImportSource": "solid-js",
+ },
+ "include": ["./src"]
+}
diff --git a/examples/checkbox-example/vite.config.js b/examples/checkbox-example/vite.config.js
new file mode 100644
index 00000000..ea2923ba
--- /dev/null
+++ b/examples/checkbox-example/vite.config.js
@@ -0,0 +1,6 @@
+import { defineConfig } from 'vite';
+import solidPlugin from 'vite-plugin-solid';
+
+export default defineConfig({
+ plugins: [solidPlugin()],
+});
diff --git a/packages/solid-headless/src/index.ts b/packages/solid-headless/src/index.ts
index a0db8f48..4ade7857 100644
--- a/packages/solid-headless/src/index.ts
+++ b/packages/solid-headless/src/index.ts
@@ -162,3 +162,13 @@ export {
ToasterListener,
useToaster,
} from './tailwind/Toast';
+export {
+ TailwindCheckbox,
+ TailwindCheckboxDescription,
+ TailwindCheckboxDescriptionProps,
+ TailwindCheckboxIndicator,
+ TailwindCheckboxIndicatorProps,
+ TailwindCheckboxLabel,
+ TailwindCheckboxLabelProps,
+ TailwindCheckboxProps,
+} from './tailwind/Checkbox';
diff --git a/packages/solid-headless/src/tailwind/Checkbox.tsx b/packages/solid-headless/src/tailwind/Checkbox.tsx
new file mode 100644
index 00000000..caf3d53f
--- /dev/null
+++ b/packages/solid-headless/src/tailwind/Checkbox.tsx
@@ -0,0 +1,205 @@
+import { JSX } from 'solid-js/jsx-runtime';
+import {
+ createContext,
+ createEffect,
+ createSignal,
+ createUniqueId,
+ onCleanup,
+ useContext,
+} from 'solid-js';
+import {
+ Dynamic,
+} from 'solid-js/web';
+import {
+ HeadlessToggleChild,
+ HeadlessToggleChildProps,
+ HeadlessToggleRoot,
+ HeadlessToggleRootProps,
+ useHeadlessToggleChild,
+} from '../headless/Toggle';
+import { DynamicProps, ValidConstructor } from '../utils/dynamic-prop';
+import { excludeProps } from '../utils/exclude-props';
+import Fragment from '../utils/Fragment';
+
+interface TailwindCheckboxContext {
+ ownerID: string;
+ labelID: string;
+ indicatorID: string;
+ descriptionID: string;
+}
+
+const TailwindCheckboxContext = createContext();
+
+function useTailwindCheckboxContext(componentName: string): TailwindCheckboxContext {
+ const context = useContext(TailwindCheckboxContext);
+
+ if (context) {
+ return context;
+ }
+ throw new Error(`<${componentName}> must be used inside a `);
+}
+
+export type TailwindCheckboxProps = {
+ as?: T;
+} & HeadlessToggleRootProps
+ & Omit, keyof HeadlessToggleRootProps>;
+
+export function TailwindCheckbox(
+ props: TailwindCheckboxProps,
+): JSX.Element {
+ const ownerID = createUniqueId();
+ const labelID = createUniqueId();
+ const indicatorID = createUniqueId();
+ const descriptionID = createUniqueId();
+
+ return (
+
+
+
+ {props.children}
+
+
+
+ );
+}
+
+export type TailwindCheckboxIndicatorProps = {
+ as?: T;
+} & HeadlessToggleChildProps
+ & Omit, keyof HeadlessToggleChildProps>;
+
+export function TailwindCheckboxIndicator(
+ props: TailwindCheckboxIndicatorProps,
+): JSX.Element {
+ const context = useTailwindCheckboxContext('TailwindCheckboxIndicator');
+ const state = useHeadlessToggleChild();
+
+ const [internalRef, setInternalRef] = createSignal();
+
+ createEffect(() => {
+ const ref = internalRef();
+
+ if (ref) {
+ const toggle = () => {
+ state.setState(!state.checked());
+ };
+
+ const onKeyDown = (e: KeyboardEvent) => {
+ if (e.key === ' ') {
+ toggle();
+ }
+ };
+
+ ref.addEventListener('click', toggle);
+ ref.addEventListener('keydown', onKeyDown);
+ onCleanup(() => {
+ ref.removeEventListener('click', toggle);
+ ref.removeEventListener('keydown', onKeyDown);
+ });
+ }
+ });
+
+ return (
+ {
+ const outerRef = props.ref;
+ if (typeof outerRef === 'function') {
+ outerRef(e);
+ } else {
+ props.ref = e;
+ }
+ setInternalRef(e);
+ }}
+ >
+
+ {props.children}
+
+
+ );
+}
+
+export type TailwindCheckboxLabelProps = {
+ as?: T;
+} & HeadlessToggleChildProps
+ & Omit, keyof HeadlessToggleChildProps>;
+
+export function TailwindCheckboxLabel(
+ props: TailwindCheckboxLabelProps,
+): JSX.Element {
+ const context = useTailwindCheckboxContext('TailwindCheckboxLabel');
+ return (
+
+ {props.children}
+
+ );
+}
+
+export type TailwindCheckboxDescriptionProps = {
+ as?: T;
+} & HeadlessToggleChildProps
+ & Omit, keyof HeadlessToggleChildProps>;
+
+export function TailwindCheckboxDescription(
+ props: TailwindCheckboxDescriptionProps,
+): JSX.Element {
+ const context = useTailwindCheckboxContext('TailwindCheckboxDescription');
+
+ return (
+
+
+ {props.children}
+
+
+ );
+}