Skip to content

Conversation

@lehju
Copy link
Contributor

@lehju lehju commented Dec 18, 2025

Description
Add accordion component.

Reference

Issues #632

Summary by CodeRabbit

Release Notes

  • New Features
    • Introduced a new Accordion component enabling collapsible content sections with support for single or multiple item expansion modes
    • Accordion items support customizable headers and content slots
    • Includes accessibility features with ARIA attributes and smooth animations

✏️ Tip: You can customize this high-level summary in your review settings.

@lehju lehju requested a review from FabianWilms December 18, 2025 15:35
@lehju lehju self-assigned this Dec 18, 2025
@lehju lehju requested a review from a team as a code owner December 18, 2025 15:35
@lehju lehju added the enhancement New feature or request label Dec 18, 2025
@lehju
Copy link
Contributor Author

lehju commented Dec 18, 2025

@coderabbitai

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

Tip

For best results, initiate chat on the files or code changes.

@lehju, hello! 👋 How can I assist you today? Feel free to ask me to review the code, explain something, generate tests, or help with any other task related to this pull request.

@lehju
Copy link
Contributor Author

lehju commented Dec 18, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

Walkthrough

Introduces a new Accordion component system comprising MucAccordion (parent) and MucAccordionItem (child) components with full state management and event handling. Includes Storybook stories for both components and exports them through index barrel files for public use.

Changes

Cohort / File(s) Summary
Accordion Components
src/components/Accordion/MucAccordion.vue, src/components/Accordion/MucAccordionItem.vue
New Vue 3 components implementing a collapsible accordion system. MucAccordion manages activeItems state, supports single/multiple item expansion, and exposes slot scope with activeItems and event handlers. MucAccordionItem is a child item with collapse/expand animations, ARIA attributes, and transitionend event listeners.
Accordion Storybook Stories
src/components/Accordion/MucAccordion.stories.ts, src/components/Accordion/MucAccordionItem.stories.ts
Story files for both accordion components with Template and Multiple story variants. Include metadata, autodocs tagging, detailed descriptions, and example usage for Storybook documentation.
Export Barrel Files
src/components/Accordion/index.ts, src/components/index.ts
Public module exports. Accordion/index.ts re-exports MucAccordion and MucAccordionItem; components/index.ts adds them to the main public API.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Areas requiring attention:

  • MucAccordionItem.vue: Verify transition state management, transitionend listener lifecycle, and reactive behavior when activeItems prop changes
  • MucAccordion.vue: Confirm single vs. multiple mode logic for activeItems updates and slot scope bindings
  • ARIA attributes and accessibility compliance in both components
  • Story examples accurately reflect intended usage patterns

Poem

🎵 A new Accordion takes the stage so bright,
Expanding items with smooth transition light,
Parent and child in harmony dance,
Slot scope and events in perfect cadence,
Stories and exports—ready to delight! 🎼

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding a new accordion component (MucAccordion and MucAccordionItem) to the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 632-add-accordion-component

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: 3

🧹 Nitpick comments (2)
src/components/Accordion/MucAccordion.vue (1)

70-76: Consider preventing duplicate IDs in multiple mode.

When multiple is true, the onOpen function pushes the ID to activeItems without checking if it already exists. While this might not cause immediate issues, it could lead to duplicate entries if onOpen is called multiple times for the same item.

🔎 View suggested improvement
 const onOpen = (id: string) => {
   if (multiple) {
-    activeItems.value.push(id);
+    if (!activeItems.value.includes(id)) {
+      activeItems.value.push(id);
+    }
   } else {
     activeItems.value = [id];
   }
 };
src/components/Accordion/MucAccordionItem.vue (1)

124-147: Height animation logic is functional but could be more robust.

The setTimeout(..., 0) pattern for forcing reflow is a known technique for CSS transitions, and the implementation is correct. However, there are a few optional improvements to consider:

  1. The nested conditionals with section.value checks could be simplified
  2. Using requestAnimationFrame instead of setTimeout(..., 0) is more semantically correct for DOM updates
💡 Optional refactoring idea using requestAnimationFrame
 const toggleCollapsable = () => {
-  if (section.value) {
+  if (!section.value) return;
+  
     collapsed.value = !collapsed.value;
     if (collapsed.value) {
       section.value.style.height = section.value.scrollHeight + "px";
       collapsing.value = true;
       emit("close", id);
-      setTimeout(() => {
-        if (section.value) {
-          section.value.style.height = "0";
-        }
-      }, 0);
+      requestAnimationFrame(() => {
+        requestAnimationFrame(() => {
+          if (section.value) {
+            section.value.style.height = "0";
+          }
+        });
+      });
     } else {
       section.value.style.height = "0";
       collapsing.value = true;
       emit("open", id);
-      setTimeout(() => {
-        if (section.value) {
-          section.value.style.height = section.value.scrollHeight + "px";
-        }
-      }, 0);
+      requestAnimationFrame(() => {
+        requestAnimationFrame(() => {
+          if (section.value) {
+            section.value.style.height = section.value.scrollHeight + "px";
+          }
+        });
+      });
     }
-  }
 };

The double requestAnimationFrame ensures the browser has painted the initial state before applying the transition.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0b7c0d and e58c448.

📒 Files selected for processing (6)
  • src/components/Accordion/MucAccordion.stories.ts (1 hunks)
  • src/components/Accordion/MucAccordion.vue (1 hunks)
  • src/components/Accordion/MucAccordionItem.stories.ts (1 hunks)
  • src/components/Accordion/MucAccordionItem.vue (1 hunks)
  • src/components/Accordion/index.ts (1 hunks)
  • src/components/index.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/Accordion/MucAccordion.stories.ts (3)
src/components/Accordion/index.ts (1)
  • MucAccordion (4-4)
src/components/index.ts (1)
  • MucAccordion (31-31)
src/components/Accordion/MucAccordionItem.stories.ts (1)
  • Template (20-37)
🔇 Additional comments (8)
src/components/index.ts (1)

1-1: Nice addition! The imports and exports follow the existing pattern perfectly.

The new Accordion components are correctly imported from the barrel and re-exported in the public API, maintaining consistency with the rest of the codebase.

Also applies to: 31-32

src/components/Accordion/index.ts (1)

1-4: Perfect barrel export! This follows the established pattern in the codebase.

Clean and straightforward re-export of the Accordion components.

src/components/Accordion/MucAccordion.vue (1)

1-27: Template structure looks great!

The component structure follows Vue 3 best practices with proper semantic HTML and ARIA-friendly setup. The slot pattern for passing state and handlers to children is a solid approach for this accordion architecture.

src/components/Accordion/MucAccordionItem.vue (3)

1-50: Template implementation looks solid!

Great use of ARIA attributes for accessibility (aria-expanded, aria-controls, aria-labelledby), and the conditional icon rendering based on collapse state is clean. The class bindings for transition states are well-structured.


105-119: Watch may not trigger on activeItems array mutations.

The watch is monitoring the activeItems reference, but since it's passed as a prop and mutated externally (via push/filter in the parent), Vue's reactivity should handle this. However, the watcher would be more explicit if it used deep: true or watched the array's contents specifically.

That said, since the parent component replaces the array reference in onClose (filter creates a new array) and in onOpen when not in multiple mode, this should work in practice.

Consider verifying the reactivity works as expected when:

  • Items are added in multiple mode (parent pushes to array)
  • Items are removed (parent filters array, creating new reference)

You could add a simple test or manually verify in Storybook that opening/closing items in both single and multiple modes works correctly.


159-172: Lifecycle hooks are properly implemented!

Nice job cleaning up the event listener in onBeforeUnmount and initializing the collapsed state based on activeItems in onMounted. This prevents memory leaks and ensures correct initial state.

src/components/Accordion/MucAccordion.stories.ts (2)

47-103: Template story demonstrates the component beautifully!

The example shows proper usage with the slot scope pattern, including the defaultItem prop to have the first item open initially. All four accordion items are correctly wired with the shared state.


105-161: Multiple story effectively showcases the multi-expand feature!

This story clearly demonstrates the multiple prop behavior, allowing several accordion items to be open simultaneously. Well done!

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 18, 2025
@lehju lehju closed this Dec 18, 2025
@lehju lehju reopened this Dec 18, 2025
Copy link
Member

@FabianWilms FabianWilms left a comment

Choose a reason for hiding this comment

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

All else is looking mighty fine!

Co-authored-by: Fabian Wilms <10800158+FabianWilms@users.noreply.github.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 19, 2025
@FabianWilms FabianWilms merged commit 23d6be2 into beta Dec 22, 2025
9 checks passed
@FabianWilms FabianWilms deleted the 632-add-accordion-component branch December 22, 2025 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants