-
Notifications
You must be signed in to change notification settings - Fork 0
Issue 64 add checkbox group component #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
99a30e0
448cc22
fb07789
4fb5ff5
85de83a
4014782
6ed6033
741cb2b
71ab22b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| "use client"; | ||
| import { useState } from "react"; | ||
|
|
||
| import { Button } from "@/components/ui/button"; | ||
| import { CheckboxGroup, CheckboxItem } from "@/components/ui/checkbox"; | ||
| import { Label } from "@/components/ui/label"; | ||
|
|
||
| const DATES = [ | ||
| "Monday", | ||
| "Tuesday", | ||
| "Wednesday", | ||
| "Thursday", | ||
| "Friday", | ||
| "Saturday", | ||
| "Sunday", | ||
| ]; | ||
|
|
||
| export default function CheckboxTestPage() { | ||
| const [acceptTerms, setAcceptTerms] = useState<boolean>(false); | ||
| const [dates, setDates] = useState<string[]>([]); | ||
|
|
||
| const handleSubmit = (e: React.FormEvent) => { | ||
| e.preventDefault(); | ||
| alert( | ||
| `Submitted data:\nacceptCondition: ${acceptTerms.toString()}\ndates: ${JSON.stringify(dates)}`, | ||
| ); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="min-h-screen p-8"> | ||
| <div className="mx-auto my-5 flex w-full max-w-lg flex-col items-center justify-center"> | ||
| <form onSubmit={handleSubmit} className="w-full rounded-md border p-4"> | ||
| {/* a single checkbox */} | ||
| <p className="title mb-3">A single checkbox</p> | ||
| <CheckboxItem | ||
| id="acceptTerms" | ||
| name="acceptTerms" | ||
| checked={acceptTerms} | ||
| onCheckedChange={(checked) => setAcceptTerms(checked === true)} // Radix Output can be true | false | "indeterminate" | ||
| > | ||
| <Label htmlFor="acceptTerms"> Accept terms and conditions. </Label> | ||
| </CheckboxItem> | ||
| {/* a checkbox group */} | ||
| <p className="title mb-3 mt-5">A checkbox group</p> | ||
| <CheckboxGroup value={dates} onValueChange={setDates}> | ||
| {DATES.map((date) => ( | ||
| <CheckboxItem key={date} value={date} id={date}> | ||
| <Label htmlFor={date}> {date} </Label> | ||
| </CheckboxItem> | ||
| ))} | ||
| </CheckboxGroup> | ||
| <Button type="submit" className="mx-auto mt-4"> | ||
| Submit | ||
| </Button> | ||
| </form> | ||
| <p className="mt-4 text-center"> | ||
| Current acceptTerms value: {acceptTerms.toString()} | ||
| </p> | ||
| <p className="mt-4 text-center"> | ||
| Current dates message: {JSON.stringify(dates, null, 1)} | ||
| </p> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,127 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Usage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A single checkbox: use [checked, setChecked] = useState<boolean>(initialValue) to get the checkbox status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // <CheckboxItem | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // checked={checked} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // onCheckedChange={(checked) => setChecked(checked === true)} // As Radix Output can be true | false | "indeterminate", simple pass setChecked will cause Typescript complaint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // // optional props can be passed as in standard html checkbox | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // {children} // add label here | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //</CheckboxItem> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A group of checkbox: use [value, setValue] = useState<string[]>(initialValue) to get the selected value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // <CheckboxGroup value={value} onValueChange={setValue}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // <CheckboxItem value={value1}>{children}</CheckboxItem> // value is a necessary field in this case | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // <CheckboxItem value={value2}>{children}</CheckboxItem> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // </CheckboxGroup> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Usage: | |
| // A single checkbox: use [checked, setChecked] = useState<boolean>(initialValue) to get the checkbox status | |
| // <CheckboxItem | |
| // checked={checked} | |
| // onCheckedChange={(checked) => setChecked(checked === true)} // As Radix Output can be true | false | "indeterminate", simple pass setChecked will cause Typescript complaint | |
| // // optional props can be passed as in standard html checkbox | |
| // > | |
| // {children} // add label here | |
| //</CheckboxItem> | |
| // A group of checkbox: use [value, setValue] = useState<string[]>(initialValue) to get the selected value | |
| // <CheckboxGroup value={value} onValueChange={setValue}> | |
| // <CheckboxItem value={value1}>{children}</CheckboxItem> // value is a necessary field in this case | |
| // <CheckboxItem value={value2}>{children}</CheckboxItem> | |
| // </CheckboxGroup> | |
| /** | |
| * Usage: | |
| * | |
| * A single checkbox: use `[checked, setChecked] = useState<boolean>(initialValue)` to get the checkbox status | |
| * ```tsx | |
| * <CheckboxItem | |
| * checked={checked} | |
| * onCheckedChange={(checked) => setChecked(checked === true)} // As Radix Output can be true | false | "indeterminate", simple pass setChecked will cause Typescript complaint | |
| * // optional props can be passed as in standard html checkbox | |
| * > | |
| * {children} // add label here | |
| * </CheckboxItem> | |
| * ``` | |
| * | |
| * A group of checkbox: use `[value, setValue] = useState<string[]>(initialValue)` to get the selected value | |
| * ```tsx | |
| * <CheckboxGroup value={value} onValueChange={setValue}> | |
| * <CheckboxItem value={value1}>{children}</CheckboxItem> // value is a necessary field in this case | |
| * <CheckboxItem value={value2}>{children}</CheckboxItem> | |
| * </CheckboxGroup> | |
| * ``` | |
| */ |
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "use client" directive is missing at the top of this file. Other similar Radix UI component files in this codebase (e.g., accordion.tsx, select.tsx) include this directive, which is necessary for components that use React hooks like useCallback and useContext in Next.js App Router.
Outdated
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This single-line comment should either be removed or converted to JSDoc format (/** ... */) to document the component, consistent with other UI components in the codebase like radio-group.tsx.
| // checkbox item | |
| /** | |
| * CheckboxItem component for rendering a single checkbox. | |
| * Can be used standalone or within a CheckboxGroup. | |
| */ |
Outdated
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The handleCheckedChange callback assumes checked is a boolean, but Radix UI's CheckedState type can be true | false | "indeterminate". This may cause runtime errors when an indeterminate state is passed. Consider handling the indeterminate state or casting to boolean: (checked: CheckedState) => context.onChange(value, checked === true)
| ? (checked: boolean) => context.onChange(value, checked) | |
| ? (checked: CheckboxPrimitive.CheckedState) => context.onChange(value, checked === true) |
Outdated
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The checkbox and label are rendered in separate elements without an explicit wrapper label element. While the htmlFor/id association works, wrapping both in a <label> element would improve click target area and accessibility. Consider wrapping the entire div content in a label element or document that labels should be passed as children and associated via htmlFor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name in the alert message is inconsistent: it shows "acceptCondition" but the actual state variable is named "acceptTerms" (line 19). This should be "acceptTerms" to match the variable name.