Skip to content

feat: add Collapsible component#660

Open
rohanchkrabrty wants to merge 1 commit intomainfrom
feat-collapsible
Open

feat: add Collapsible component#660
rohanchkrabrty wants to merge 1 commit intomainfrom
feat-collapsible

Conversation

@rohanchkrabrty
Copy link
Contributor

@rohanchkrabrty rohanchkrabrty commented Feb 26, 2026

Summary

  • Add new Collapsible component based on Base UI with Root, Trigger, and Panel sub-components
  • Include animated expand/collapse transition using --collapsible-panel-height CSS variable
  • Add unit tests covering rendering, open/close behavior, controlled state, keyboard interaction, and disabled state
  • Add documentation with preview, controlled, default open, and disabled examples
  • Add playground example

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new Collapsible component for expandable content sections
    • Supports controlled and default-open states with disabled variant
    • Fully keyboard accessible (Enter/Space key support)
  • Documentation

    • Added comprehensive documentation with interactive code examples
    • Includes common implementation patterns and accessibility guidelines

@vercel
Copy link

vercel bot commented Feb 26, 2026

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

Project Deployment Actions Updated (UTC)
apsara Building Building Preview, Comment Feb 26, 2026 8:18pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

This PR introduces a complete Collapsible UI component to the design system, including the core React component built on @base-ui/react primitives, CSS styling with animation support, comprehensive test coverage, TypeScript prop interfaces, MDX documentation with examples, and playground demonstrations.

Changes

Cohort / File(s) Summary
Core Collapsible Component
packages/raystack/components/collapsible/collapsible.tsx, packages/raystack/components/collapsible/collapsible.module.css, packages/raystack/components/collapsible/index.ts, packages/raystack/index.tsx
New forwardRef-based component wrapper around @base-ui/react primitives with Collapsible.Trigger and Collapsible.Panel nested exports; CSS module defines trigger styles with disabled state and panel height animations using CSS variables and transitions.
Component Tests
packages/raystack/components/collapsible/__tests__/collapsible.test.tsx
Comprehensive test suite covering rendering, open/close behavior with aria-expanded, defaultOpen, controlled state, onOpenChange callbacks, keyboard interactions (Enter/Space), disabled state handling, ref forwarding, and custom className propagation.
Documentation & Props
apps/www/src/content/docs/components/collapsible/props.ts, apps/www/src/content/docs/components/collapsible/demo.ts, apps/www/src/content/docs/components/collapsible/index.mdx
TypeScript interfaces defining CollapsibleProps, CollapsibleTriggerProps, and CollapsiblePanelProps; four code-backed demo exports (preview, controlledDemo, defaultOpenDemo, disabledDemo); MDX documentation with anatomy, examples, API references, and accessibility guidelines.
Playground Examples
apps/www/src/components/playground/collapsible-examples.tsx, apps/www/src/components/playground/index.ts
New PlaygroundLayout component rendering three Collapsible variants (default, defaultOpen, disabled) with Flex column layouts and text labels; added re-export in playground index.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

Do not merge

Suggested reviewers

  • paanSinghCoder
  • rsbh

Poem

A collapsible friend hops into place, 🐰
With triggers that spring and panels that embrace,
Through base-ui's foundation, styled with grace,
Tests verify every click and space—
Documentation blooms in the marketplace! 🌱

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Collapsible component' clearly and concisely summarizes the main change: introducing a new Collapsible component. It accurately reflects the primary objective of the PR.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-collapsible

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.

Copy link
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 (2)
packages/raystack/components/collapsible/collapsible.module.css (1)

11-15: Respect reduced-motion preferences for panel animation.

Consider disabling the height transition for users who prefer reduced motion.

Suggested refinement
 .panel {
   height: var(--collapsible-panel-height);
   overflow: hidden;
   transition: height 150ms ease-out;
 }
+
+@media (prefers-reduced-motion: reduce) {
+  .panel {
+    transition: none;
+  }
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/collapsible/collapsible.module.css` around lines
11 - 15, The .panel CSS rule currently animates height; add a
prefers-reduced-motion media query that disables the height transition for users
who prefer reduced motion by overriding .panel (the same selector) to set
transition: none (or remove height animation) so the panel opens/closes
instantly while keeping the existing --collapsible-panel-height and overflow
behavior intact.
apps/www/src/content/docs/components/collapsible/props.ts (1)

1-16: Clarify controlled vs uncontrolled prop usage in docs.

Please add a short note that open (controlled) and defaultOpen (uncontrolled) are alternative modes and should not be used together to avoid ambiguous state ownership.

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

In `@apps/www/src/content/docs/components/collapsible/props.ts` around lines 1 -
16, Update the CollapsibleProps interface comments to clarify that open and
defaultOpen are alternative modes and should not be used together: in the JSDoc
for the open property (and/or at the top of the interface) add a short note
stating that open is the controlled mode, defaultOpen is the uncontrolled mode,
and using both at once leads to ambiguous state ownership and should be avoided;
reference the CollapsibleProps interface and the open and defaultOpen property
names so readers can find the guidance easily.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/raystack/components/collapsible/collapsible.module.css`:
- Around line 1-4: The .trigger rule currently removes the default keyboard
focus indicator (outline: none) which breaks accessibility; restore a visible
focus style by removing the blanket outline:none or override it with a dedicated
:focus-visible (or :focus) rule for .trigger that applies a clear high-contrast
outline or box-shadow (e.g., 2px outline or visible ring) so keyboard users can
see focus, keeping cursor: pointer intact and ensuring the focus style meets
contrast/visibility requirements for .trigger.

---

Nitpick comments:
In `@apps/www/src/content/docs/components/collapsible/props.ts`:
- Around line 1-16: Update the CollapsibleProps interface comments to clarify
that open and defaultOpen are alternative modes and should not be used together:
in the JSDoc for the open property (and/or at the top of the interface) add a
short note stating that open is the controlled mode, defaultOpen is the
uncontrolled mode, and using both at once leads to ambiguous state ownership and
should be avoided; reference the CollapsibleProps interface and the open and
defaultOpen property names so readers can find the guidance easily.

In `@packages/raystack/components/collapsible/collapsible.module.css`:
- Around line 11-15: The .panel CSS rule currently animates height; add a
prefers-reduced-motion media query that disables the height transition for users
who prefer reduced motion by overriding .panel (the same selector) to set
transition: none (or remove height animation) so the panel opens/closes
instantly while keeping the existing --collapsible-panel-height and overflow
behavior intact.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d24df8 and 055c656.

📒 Files selected for processing (10)
  • apps/www/src/components/playground/collapsible-examples.tsx
  • apps/www/src/components/playground/index.ts
  • apps/www/src/content/docs/components/collapsible/demo.ts
  • apps/www/src/content/docs/components/collapsible/index.mdx
  • apps/www/src/content/docs/components/collapsible/props.ts
  • packages/raystack/components/collapsible/__tests__/collapsible.test.tsx
  • packages/raystack/components/collapsible/collapsible.module.css
  • packages/raystack/components/collapsible/collapsible.tsx
  • packages/raystack/components/collapsible/index.ts
  • packages/raystack/index.tsx

Comment on lines +1 to +4
.trigger {
cursor: pointer;
outline: none;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore visible keyboard focus styling on the trigger.

Line 3 removes the default focus indicator (outline: none) but no replacement focus style is defined, which is an accessibility blocker for keyboard users.

Suggested fix
 .trigger {
   cursor: pointer;
-  outline: none;
 }
+
+.trigger:focus-visible {
+  outline: 2px solid var(--rs-color-border-primary, currentColor);
+  outline-offset: 2px;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.trigger {
cursor: pointer;
outline: none;
}
.trigger {
cursor: pointer;
}
.trigger:focus-visible {
outline: 2px solid var(--rs-color-border-primary, currentColor);
outline-offset: 2px;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/collapsible/collapsible.module.css` around lines
1 - 4, The .trigger rule currently removes the default keyboard focus indicator
(outline: none) which breaks accessibility; restore a visible focus style by
removing the blanket outline:none or override it with a dedicated :focus-visible
(or :focus) rule for .trigger that applies a clear high-contrast outline or
box-shadow (e.g., 2px outline or visible ring) so keyboard users can see focus,
keeping cursor: pointer intact and ensuring the focus style meets
contrast/visibility requirements for .trigger.

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.

1 participant