Checkbox
A checkbox component for capturing boolean input with support for checked, unchecked, and indeterminate states.
import { Checkbox, CheckboxLabel } from "~/components/checkbox";
export default function CheckboxBasicDemo() {
return (
<Checkbox defaultChecked>
<CheckboxLabel>Accept terms</CheckboxLabel>
</Checkbox>
);
}Installation
CLI
Run the following command to add the component to your project:
npx @ark-preset/cli@latest add checkboxManual
Create the recipe file at src/components/recipes/checkbox.ts:
import { tv, type VariantProps } from "tailwind-variants";
export const checkboxVariants = tv({
slots: {
root: "inline-flex items-center gap-2 data-disabled:opacity-50 data-disabled:cursor-not-allowed",
control:
"peer size-4 shrink-0 rounded-sm border border-input ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:border-primary",
indicator: "flex items-center justify-center text-current",
},
});
export type CheckboxVariants = VariantProps<typeof checkboxVariants>;Create the component directory and files.
src/components/checkbox/checkbox.base.tsx:
import { Checkbox as ArkCheckbox } from "@ark-ui/solid/checkbox";
import { splitProps, type Component } from "solid-js";
import { checkboxVariants, labelVariants } from "../recipes/checkbox";
const styles = checkboxVariants();
const CheckboxRoot: Component<ArkCheckbox.RootProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCheckbox.Root class={styles.root({ class: local.class })} {...others} />;
};
const CheckboxRootProvider: Component<ArkCheckbox.RootProviderProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCheckbox.RootProvider class={styles.root({ class: local.class })} {...others} />;
};
const CheckboxControl: Component<ArkCheckbox.ControlProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCheckbox.Control class={styles.control({ class: local.class })} {...others} />;
};
const CheckboxLabel: Component<ArkCheckbox.LabelProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCheckbox.Label class={labelVariants({ class: local.class })} {...others} />;
};
const CheckboxIndicator: Component<ArkCheckbox.IndicatorProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCheckbox.Indicator class={styles.indicator({ class: local.class })} {...others} />;
};
const CheckboxHiddenInput = ArkCheckbox.HiddenInput;
const CheckboxGroup = ArkCheckbox.Group;
const CheckboxGroupProvider = ArkCheckbox.GroupProvider;
export const Checkbox = {
Root: CheckboxRoot,
RootProvider: CheckboxRootProvider,
Control: CheckboxControl,
Label: CheckboxLabel,
Indicator: CheckboxIndicator,
HiddenInput: CheckboxHiddenInput,
Group: CheckboxGroup,
GroupProvider: CheckboxGroupProvider,
};src/components/checkbox/index.tsx:
import { Checkbox as ArkCheckbox } from "@ark-ui/solid/checkbox";
import { splitProps, type Component } from "solid-js";
import { Checkbox as CheckboxBase } from "./checkbox.base";
const CheckboxLabel = CheckboxBase.Label;
const CheckboxControl = () => (
<>
<CheckboxBase.Control>
<CheckboxBase.Indicator>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="size-3.5"
>
<path d="M20 6 9 17l-5-5" />
</svg>
</CheckboxBase.Indicator>
<CheckboxBase.Indicator indeterminate>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="size-3.5"
>
<path d="M5 12h14" />
</svg>
</CheckboxBase.Indicator>
</CheckboxBase.Control>
<CheckboxBase.HiddenInput />
</>
);
const Checkbox: Component<ArkCheckbox.RootProps> = (props) => {
const [local, others] = splitProps(props, ["class", "children"]);
return (
<CheckboxBase.Root class={local.class} {...others}>
<CheckboxControl />
{local.children}
</CheckboxBase.Root>
);
};
const CheckboxRootProvider: Component<ArkCheckbox.RootProviderProps> = (props) => {
const [local, others] = splitProps(props, ["class", "children"]);
return (
<CheckboxBase.RootProvider class={local.class} {...others}>
<CheckboxControl />
{local.children}
</CheckboxBase.RootProvider>
);
};
export { Checkbox, CheckboxRootProvider, CheckboxLabel, CheckboxBase };
export { checkboxVariants, type CheckboxVariants } from "../recipes/checkbox";Note: Make sure your project has the Tailwind CSS theme variables set up (
--background,--foreground,--ring,--border, etc.) or override the utility classes to match your design system.
Usage
Basic Usage
import { Checkbox, CheckboxLabel } from "~/components/checkbox";
export default function CheckboxBasicDemo() {
return (
<Checkbox defaultChecked>
<CheckboxLabel>Accept terms</CheckboxLabel>
</Checkbox>
);
}Disabled
Add the disabled prop to disable interaction.
import { Checkbox, CheckboxLabel } from "~/components/checkbox";
export default function CheckboxDisabledDemo() {
return (
<Checkbox disabled>
<CheckboxLabel>Accept terms</CheckboxLabel>
</Checkbox>
);
}Indeterminate
Set the checked prop to “indeterminate” for an indeterminate state.
import { Checkbox, CheckboxLabel } from "~/components/checkbox";
export default function CheckboxIndeterminateDemo() {
return (
<Checkbox checked="indeterminate">
<CheckboxLabel>Accept terms</CheckboxLabel>
</Checkbox>
);
}Advanced Usage
Root Provider
Use CheckboxRootProvider when you need to access the checkbox state outside of the checkbox tree. This pattern uses the useCheckbox hook from Ark UI to create a shared context that both the checkbox and external elements can reference.
import { useCheckbox } from "@ark-ui/solid/checkbox";
import { CheckboxRootProvider, CheckboxLabel } from "~/components/checkbox";
export default function CheckboxRootProviderDemo() {
const checkbox = useCheckbox({ defaultChecked: true });
return (
<div class="space-y-4">
<output class="block text-sm text-muted-foreground">
Checked: {JSON.stringify(checkbox().checked)}
</output>
<CheckboxRootProvider value={checkbox}>
<CheckboxLabel>Subscribe to newsletter</CheckboxLabel>
</CheckboxRootProvider>
</div>
);
}The key difference:
Checkbox(Root) — manages its own state internally. Use for simple, self-contained checkboxes.CheckboxRootProvider— accepts a pre-created checkbox context viauseCheckbox. Use when you need to read or control the checkbox state from outside the component tree.
API Reference
See the Ark UI Checkbox documentation.