iTranslated by AI
Implementation Guide for Checkbox with shadcn/ui and conform
Related Articles
Please also see other articles in this series:
- Implementation guide for Input with shadcn/ui and conform
- Implementation guide for Textarea with shadcn/ui and conform
- Implementation guide for Select with shadcn/ui and conform
- Implementation guide for Checkbox with shadcn/ui and conform
- Implementation guide for Switch with shadcn/ui and conform
- Implementation guide for RadioGroup with shadcn/ui and conform
By combining these articles, you can gain comprehensive knowledge of form implementation using shadcn/ui and conform.
Overview
In this article, we will explain how to implement a basic Checkbox using shadcn/ui and conform. We will introduce both the standard implementation method and a method using custom helper functions.
For the specifications and usage of the shadcn/ui Checkbox component itself, please refer to the official website.
Setup
First, import the necessary libraries.
import { useForm } from '@conform-to/react'
import { getZodConstraint, parseWithZod } from '@conform-to/zod'
import { z } from 'zod'
import { Checkbox } from '~/components/ui/checkbox'
import { Label } from '~/components/ui/label'
import { getCheckboxProps } from './helper'
The basic form structure is as follows:
export default function CheckboxForm() {
const [form, fields] = useForm({
onValidate: ({ formData }) => parseWithZod(formData, { schema }),
constraint: getZodConstraint(schema),
shouldValidate: 'onBlur',
shouldRevalidate: 'onInput',
})
return (
<form {...getFormProps(form)} method="post">
{/* Checkbox fields will be placed here */}
</form>
)
}
Schema Definition
const schema = z.object({
agreeTerms: z.boolean({
required_error: 'Please agree to the terms of service',
message: 'Invalid selection',
})
})
Implementation Examples
1. Basic Checkbox Implementation
<div className="flex items-center space-x-2">
<Checkbox
key={fields.agreeTerms.key}
id={fields.agreeTerms.id}
name={fields.agreeTerms.name}
required={fields.agreeTerms.required}
defaultChecked={fields.agreeTerms.initialValue === 'on'}
aria-invalid={!fields.agreeTerms.valid || undefined}
aria-describedby={!fields.agreeTerms.valid ? fields.agreeTerms.errorId : undefined}
onCheckedChange={(checked) => {
form.update({
name: fields.agreeTerms.name,
value: checked,
})
}}
/>
<Label
htmlFor={fields.agreeTerms.id}
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Agree to the terms of service
</Label>
</div>
<div id={fields.agreeTerms.errorId} className="text-destructive">
{fields.agreeTerms.errors}
</div>
2. Checkbox Implementation using Helper Functions
You can implement it more concisely using the getCheckboxProps function defined in the helper.ts file.
<div className="flex items-center space-x-2">
<Checkbox
{...getCheckboxProps(fields.agreeTerms)}
key={fields.agreeTerms.key}
onCheckedChange={(checked) => {
form.update({
name: fields.agreeTerms.name,
value: checked,
})
}}
/>
<Label
htmlFor={fields.agreeTerms.id}
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Agree to the terms of service
</Label>
</div>
<div id={fields.agreeTerms.errorId} className="text-destructive">
{fields.agreeTerms.errors}
</div>
Explanation of the Helper Function
In the helper.ts file, the getCheckboxProps function is defined to simplify the implementation of the Checkbox:
import type { FieldMetadata } from '@conform-to/react';
/**
* Cleanup `undefined` from the result.
* To minimize conflicts when merging with user defined props
*/
function simplify<Props>(props: Props): Props {
for (const key in props) {
if (props[key] === undefined) {
delete props[key];
}
}
return props;
}
export const getCheckboxProps = <Schema>(
metadata: FieldMetadata<Schema>,
options:
| {
ariaAttributes?: true;
ariaInvalid?: 'errors' | 'allErrors';
ariaDescribedBy?: string;
value?: boolean;
}
| {
ariaAttributes: false;
value?: boolean;
} = {
ariaAttributes: true,
}
) => {
const props: {
id: string;
key?: string;
required?: boolean;
name: string;
defaultChecked?: boolean;
'aria-invalid'?: boolean;
'aria-describedby'?: string;
} = {
id: metadata.id,
key: metadata.key,
required: metadata.required,
name: metadata.name,
};
if (typeof options.value === 'undefined' || options.value) {
props.defaultChecked = metadata.initialValue === 'on';
}
if (options.ariaAttributes) {
const invalid =
options.ariaInvalid === 'allErrors'
? !metadata.valid
: typeof metadata.errors !== 'undefined';
const ariaDescribedBy = options.ariaDescribedBy;
props['aria-invalid'] = invalid || undefined;
props['aria-describedby'] = invalid
? `${metadata.errorId} ${ariaDescribedBy ?? ''}`.trim()
: ariaDescribedBy;
}
return simplify(props);
};
This function generates the following properties:
-
id: Checkbox ID -
key: React key attribute -
required: Whether it is a required field -
name: Field name -
defaultChecked: Initial checked state -
aria-invalid: Whether the input is invalid -
aria-describedby: Associates the error message
By using these properties, you can maintain a consistent implementation while considering accessibility.
Debugging and Testing
You can add a debug section to check the form values and errors:
<div>
<h3>Form values</h3>
<pre>{JSON.stringify(form.value, null, 2)}</pre>
</div>
<div>
<h3>Form errors</h3>
<pre>{JSON.stringify(form.allErrors, null, 2)}</pre>
</div>
This allows you to easily verify the state of the form.
Demo and Implementation Examples
If you want to see the actual behavior of what was explained in this article, please check the following demo page:
Form implementation demo using shadcn/ui and conform
On this demo page, you can see implementation examples for various form elements combining shadcn/ui and conform. You can check the behavior of each element, which is useful for understanding the actual user experience.
Also, you can access the source code for the implementation from the demo page. By referring to the source code, you can see in detail how the implementation methods explained in this article are applied.
By checking both the demo and the source code, you can deepen your understanding from both theoretical and practical perspectives. Please visit the demo page to check the actual behavior and code details.
Summary
By combining shadcn/ui and conform, you can easily implement a basic Checkbox. Furthermore, by using custom helper functions, you can make your code more concise and improve maintainability. By performing appropriate validation and error handling, you can create user-friendly checkbox forms.
Next time, I will explain how to implement Switch in detail. Stay tuned!
Discussion