Skip to content

feat(checkbox): accessibility features, size variants, and custom icons#741

Open
rohanchkrabrty wants to merge 4 commits intomainfrom
feat/604-checkbox-accessibility-features
Open

feat(checkbox): accessibility features, size variants, and custom icons#741
rohanchkrabrty wants to merge 4 commits intomainfrom
feat/604-checkbox-accessibility-features

Conversation

@rohanchkrabrty
Copy link
Copy Markdown
Contributor

@rohanchkrabrty rohanchkrabrty commented Apr 14, 2026

Summary

  • A2: Add [data-readonly] styling with reduced opacity and default cursor
  • A4: Fix disabled+checked/indeterminate hover bug that visually "unchecked" disabled checkboxes on hover. Added pointer-events: none and explicit state-preserving rules
  • A5: Add indeterminate hover feedback with a distinct background shade
  • F1: Add size prop with small (12px) and large (16px, default) variants via CVA. SVG icons now scale to 100% of container
  • F2: Support custom indicator via render prop — extracted from checkbox props and passed to the Indicator primitive. Receives (props, state) with checked and indeterminate
  • F4: Add orientation prop to CheckboxGroup ('vertical' default, 'horizontal')
  • Updated props documentation and playground demos for new features

Scoped out

  • Focus-visible ring (cross-cutting concern, will be handled separately)
  • Explicit inputRef/parent typing (already exposed via Base UI's CheckboxPrimitive.Root.Props)

Test plan

  • All 53 checkbox tests pass (36 checkbox + 17 group)
  • New tests for size variants (small, large, default large)
  • New tests for custom indicator via render prop (checked state, indeterminate state)
  • New tests for required prop emitting data-required
  • New tests for group orientation (vertical, horizontal)
  • No new type errors introduced

🤖 Generated with Claude Code

…ns, and group orientation

Add focus-visible ring (WCAG 2.4.7), readOnly styling, invalid/required
state styling, fix disabled+checked hover bug, add indeterminate hover
feedback, size variants (small/large), custom icon props (checkedIcon,
indeterminateIcon), explicit parent/inputRef prop types, and
CheckboxGroup orientation prop (vertical/horizontal).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview, Comment Apr 15, 2026 9:12pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Warning

Rate limit exceeded

@rohanchkrabrty has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 58 minutes and 46 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 58 minutes and 46 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd2145e6-e81c-4a1a-ac18-70fb31b9d70e

📥 Commits

Reviewing files that changed from the base of the PR and between 22682dc and 3cfff8a.

📒 Files selected for processing (2)
  • apps/www/src/content/docs/components/checkbox/index.mdx
  • apps/www/src/content/docs/components/checkbox/props.ts
📝 Walkthrough

Walkthrough

This PR extends the Checkbox and CheckboxGroup components with new customization options. It introduces a size prop to the Checkbox component supporting 'small' and 'large' variants (defaulting to 'large'), adds a render prop for custom indicator rendering with access to checkbox state, and adds an orientation prop to CheckboxGroup to control layout direction. The changes include corresponding CSS styling (size variants, horizontal group layout, disabled state refinements), updated component prop interfaces, and comprehensive test coverage for the new features.

Possibly related issues

  • [Checkbox] Feature enhancements and styling fixes #604: This PR directly implements the size variants, render prop for custom indicator rendering, and orientation prop features for the Checkbox/CheckboxGroup components along with associated CSS styling and state selector enhancements.

Suggested reviewers

  • rsbh
  • paanSinghCoder
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: accessibility features (data-readonly, data-invalid), size variants (small/large), and custom icons (render prop for indicators).
Description check ✅ Passed The pull request description clearly relates to the changeset, detailing accessibility features, size variants, custom indicator support, and group orientation for the Checkbox component.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…visible ring

- Remove focus-visible CSS (cross-cutting concern, not checkbox-specific)
- Replace checkedIcon/indeterminateIcon props with children prop that
  accepts ReactNode or render function receiving { checked, indeterminate }
- Remove explicit inputRef/parent from CheckboxItemProps (already
  exposed via Base UI's CheckboxPrimitive.Root.Props)
- Update tests and docs accordingly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…dicator

Extract render from checkbox props and pass it to the Indicator
primitive. When no render prop is provided, falls back to default
CheckMarkIcon/IndeterminateIcon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/raystack/components/checkbox/checkbox.tsx (1)

84-94: Explicitly type the render prop for the indicator component.

The render prop is inherited from CheckboxPrimitive.Root.Props but is only used for CheckboxPrimitive.Indicator. This creates an implicit type mismatch since Root.render and Indicator.render serve different purposes. Explicitly declare the render prop to improve type clarity:

♻️ Proposed fix to explicitly type the render prop
 interface CheckboxItemProps
   extends CheckboxPrimitive.Root.Props,
-    VariantProps<typeof checkboxVariants> {}
+    VariantProps<typeof checkboxVariants> {
+  /** Custom render function for the indicator. */
+  render?: CheckboxPrimitive.Indicator.Props['render'];
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/checkbox/checkbox.tsx` around lines 84 - 94,
Override the inherited ambiguous render type by omitting render from
CheckboxPrimitive.Root.Props and explicitly re-declare it using the Indicator's
render type: change CheckboxItemProps to extend
Omit<CheckboxPrimitive.Root.Props, "render"> and add render?:
CheckboxPrimitive.IndicatorProps["render"]; keep the rest of the props
(VariantProps<typeof checkboxVariants>) and the CheckboxItem function signature
the same so CheckboxPrimitive.Indicator receives the correctly typed render
prop.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/www/src/content/docs/components/checkbox/props.ts`:
- Around line 44-50: Update the JSDoc for the render prop so it documents the
full state shape passed to the custom indicator renderer: include
transitionStatus of type TransitionStatus alongside checked and indeterminate.
Specifically, modify the comment on the render?: (props:
React.HTMLAttributes<HTMLSpanElement>, state: { checked: boolean; indeterminate:
boolean }) => React.ReactNode to show state: { checked: boolean; indeterminate:
boolean; transitionStatus: TransitionStatus } and mention it mirrors
Checkbox.Indicator's state.

---

Nitpick comments:
In `@packages/raystack/components/checkbox/checkbox.tsx`:
- Around line 84-94: Override the inherited ambiguous render type by omitting
render from CheckboxPrimitive.Root.Props and explicitly re-declare it using the
Indicator's render type: change CheckboxItemProps to extend
Omit<CheckboxPrimitive.Root.Props, "render"> and add render?:
CheckboxPrimitive.IndicatorProps["render"]; keep the rest of the props
(VariantProps<typeof checkboxVariants>) and the CheckboxItem function signature
the same so CheckboxPrimitive.Indicator receives the correctly typed render
prop.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0fc64279-8568-4794-a23e-501fb4e0e999

📥 Commits

Reviewing files that changed from the base of the PR and between 26e02f6 and 22682dc.

📒 Files selected for processing (6)
  • apps/www/src/content/docs/components/checkbox/demo.ts
  • apps/www/src/content/docs/components/checkbox/props.ts
  • packages/raystack/components/checkbox/__tests__/checkbox-group.test.tsx
  • packages/raystack/components/checkbox/__tests__/checkbox.test.tsx
  • packages/raystack/components/checkbox/checkbox.module.css
  • packages/raystack/components/checkbox/checkbox.tsx

Comment on lines +44 to +50
/**
* Custom render function for the indicator. Receives `(props, state)` where state includes `checked` and `indeterminate`.
*/
render?: (
props: React.HTMLAttributes<HTMLSpanElement>,
state: { checked: boolean; indeterminate: boolean }
) => React.ReactNode;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

@base-ui/react Checkbox.Indicator render prop signature state object

💡 Result:

The render prop signature for Checkbox.Indicator in @base-ui/react is: render?: ReactElement | ((props: HTMLProps, state: Checkbox.Indicator.State) => ReactElement) | undefined The state object (Checkbox.Indicator.State) includes at minimum: - transitionStatus: TransitionStatus From analogous components like Radio.Indicator.State, it likely also includes: - checked: boolean The official Base UI documentation shows this signature explicitly for the render prop, confirming it receives props and state parameters. The exact full shape of Checkbox.Indicator.State is partially documented as having transitionStatus, with checked inferred from patterns in related components (Radio, Checkbox.Root.State).

Citations:


🏁 Script executed:

# Try to find the Base UI checkbox types in node_modules if available
# or search for any type definitions in the codebase that reference Base UI's Indicator state
find . -type f -name "*.ts" -o -name "*.tsx" | head -20 | xargs grep -l "Checkbox.Indicator.State\|CheckboxPrimitive.Indicator" 2>/dev/null | head -5

Repository: raystack/apsara

Length of output: 41


🏁 Script executed:

# Search for actual render prop usage on checkbox indicators
rg "render\s*[=:].*\(props.*state" apps/www/src --type ts --type tsx -A 3

Repository: raystack/apsara

Length of output: 86


🏁 Script executed:

# Check the structure of the codebase first
ls -la apps/www/src/content/docs/components/checkbox/

# Search for render prop usage with correct rg syntax
rg "render.*\(.*state" apps/www/src -t ts -A 2

# Also search in the entire repo for any references to Indicator state
rg "Indicator.*State\|CheckboxIndicator" . -t ts -t js

Repository: raystack/apsara

Length of output: 658


🏁 Script executed:

# Check if Base UI types are in node_modules
find . -path ./node_modules/@base-ui -name "*checkbox*" -type f 2>/dev/null | head -10

# Or look for package.json to see the Base UI version
cat package.json 2>/dev/null | grep -A 2 "@base-ui"

Repository: raystack/apsara

Length of output: 41


🏁 Script executed:

# Find the actual checkbox component implementation
find apps/www/src -name "*.ts" -o -name "*.tsx" | xargs grep -l "CheckboxPrimitive\|Checkbox.Indicator\|render.*props.*state" 2>/dev/null

# Look at the demo.ts file to see how the component is used
cat -n apps/www/src/content/docs/components/checkbox/demo.ts

Repository: raystack/apsara

Length of output: 5324


🏁 Script executed:

# Check what version of Base UI is being used and look for type definitions
find . -name "package.json" -type f | head -3 | xargs grep -l "@base-ui" 2>/dev/null

Repository: raystack/apsara

Length of output: 43


🏁 Script executed:

# Show lines 38-55 of props.ts to see the render prop documentation
sed -n '38,55p' apps/www/src/content/docs/components/checkbox/props.ts

Repository: raystack/apsara

Length of output: 499


🏁 Script executed:

# Search for the actual Checkbox component implementation
find apps -name "*.ts" -o -name "*.tsx" | xargs grep -l "Checkbox.*Indicator\|render.*props.*state" 2>/dev/null | grep -v node_modules | head -5

Repository: raystack/apsara

Length of output: 113


🏁 Script executed:

# Look for any TypeScript type definitions for Checkbox
find apps -name "*.ts" -type f | xargs grep -l "interface.*Checkbox\|type.*Checkbox" 2>/dev/null | head -10

Repository: raystack/apsara

Length of output: 113


Update the render prop state type documentation to include transitionStatus.

The documented state signature { checked: boolean; indeterminate: boolean } is incomplete. Base UI's Checkbox.Indicator state also includes transitionStatus: TransitionStatus, which is not reflected in the current documentation. Update the JSDoc comment to accurately represent the full state shape that the render function receives.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/content/docs/components/checkbox/props.ts` around lines 44 - 50,
Update the JSDoc for the render prop so it documents the full state shape passed
to the custom indicator renderer: include transitionStatus of type
TransitionStatus alongside checked and indeterminate. Specifically, modify the
comment on the render?: (props: React.HTMLAttributes<HTMLSpanElement>, state: {
checked: boolean; indeterminate: boolean }) => React.ReactNode to show state: {
checked: boolean; indeterminate: boolean; transitionStatus: TransitionStatus }
and mention it mirrors Checkbox.Indicator's state.

…ssibility props

The docs were missing sections for size variants and horizontal group
orientation that were added in the component. Also documents readOnly,
required props and the new CSS-driven accessibility states (disabled,
read-only, invalid visual feedback).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Checkbox] Feature enhancements and styling fixes

1 participant