Skip to content

feat(Sidebar): add resizable functionality#6340

Open
mikenewbon wants to merge 7 commits intonuxt:v4from
mikenewbon:feat/sidebar-resizable
Open

feat(Sidebar): add resizable functionality#6340
mikenewbon wants to merge 7 commits intonuxt:v4from
mikenewbon:feat/sidebar-resizable

Conversation

@mikenewbon
Copy link
Copy Markdown
Contributor

🔗 Linked issue

Discussion in #6038

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

The new sidebar component is great, I have a similar pattern built into my own apps, but without the resizing I still couldn't use it. I've reused the composables from dashboard sidebar and tried to mimic as much of the patterns used there.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@github-actions github-actions bot added the v4 #4488 label Apr 12, 2026
@mikenewbon
Copy link
Copy Markdown
Contributor Author

@benjamincanac ha, sorry about that, misread the silence! Reopening this. No rush on review, happy to address feedback whenever you get to it - was just trying to avoid being part of the spam/bloat train 😅

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8438b49-fedf-4cd8-92cc-ca9d9bcc2b41

📥 Commits

Reviewing files that changed from the base of the PR and between 25fdc5d and a8c6967.

📒 Files selected for processing (1)
  • src/runtime/components/Sidebar.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/runtime/components/Sidebar.vue

📝 Walkthrough

Walkthrough

Adds optional resizable behavior to Sidebar: new resizable prop plus sizing props (id, minSize, maxSize, defaultSize, collapsedSize), integrates useResizable for drag/collapse handling, updates rail slot signature to include mouse/touch/double-click handlers, and conditions rail click behavior on resizable. Runtime Sidebar sets CSS variables (--sidebar-width, --sidebar-width-icon), data-dragging state, and a ref when resizable. Theme styles adjust transitions and apply select-none while dragging. Documentation examples and pages are updated to describe the new props and behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main enhancement: adding resizable functionality to the Sidebar component, which aligns with the primary changes across all modified files.
Description check ✅ Passed The description is directly related to the changeset, explaining the enhancement context, the approach taken (reusing composables from dashboard sidebar), and confirming that documentation has been updated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
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.

🧹 Nitpick comments (2)
src/runtime/components/Sidebar.vue (2)

239-241: Consider adding a clarifying comment for the sync condition.

The condition isCollapsed.value === v works correctly because modelOpen and isCollapsed have inverted semantics (when they're the same boolean value, they're actually out of sync). However, this logic is non-obvious at first glance.

💡 Suggested clarification
 watch(modelOpen, (v) => {
+  // isCollapsed and modelOpen have inverted semantics, so same values mean out-of-sync
   if (!isMobile.value && canCollapse.value && isCollapsed.value === v) collapse(!v)
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/components/Sidebar.vue` around lines 239 - 241, Add a short
clarifying comment above the watch(...) that explains the inverted semantics:
note that modelOpen and isCollapsed purposely have opposite meanings (when
modelOpen.value === isCollapsed.value they are out of sync), so the check
isCollapsed.value === v is intentional and collapse(!v) flips the UI to sync
them; keep the existing guards (isMobile, canCollapse) and reference the watch,
modelOpen, isMobile, canCollapse, isCollapsed, and collapse symbols in the
comment so future readers understand the non‑obvious boolean inversion.

388-391: Event handler pattern works but has a subtle inefficiency.

When isResizable is false, handleMouseDown($event) is still evaluated (the function call is prepared even though undefined is returned). While functionally correct, you could simplify with conditional binding.

That said, this is a minor nitpick and the current approach is readable. No action required unless you prefer the alternative pattern.

💡 Alternative using short-circuit evaluation
-            `@mousedown`="isResizable ? handleMouseDown($event) : undefined"
-            `@touchstart`="isResizable ? handleTouchStart($event) : undefined"
-            `@dblclick`="isResizable ? handleDoubleClick($event) : undefined"
+            `@mousedown`="isResizable && handleMouseDown($event)"
+            `@touchstart`="isResizable && handleTouchStart($event)"
+            `@dblclick`="isResizable && handleDoubleClick($event)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/components/Sidebar.vue` around lines 388 - 391, The template
currently conditionally calls handlers with ternaries (e.g.,
`@mousedown`="isResizable ? handleMouseDown($event) : undefined") which still
evaluates the call expression; replace these with short-circuit bindings so the
handler function reference is only used when isResizable is true: change
`@mousedown`, `@touchstart`, and `@dblclick` to use expressions like
`@mousedown`="isResizable && handleMouseDown", `@touchstart`="isResizable &&
handleTouchStart", `@dblclick`="isResizable && handleDoubleClick" (leave
`@click`="onRailClick" as-is); this uses isResizable, handleMouseDown,
handleTouchStart, and handleDoubleClick to avoid unnecessary call-site
preparation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/runtime/components/Sidebar.vue`:
- Around line 239-241: Add a short clarifying comment above the watch(...) that
explains the inverted semantics: note that modelOpen and isCollapsed purposely
have opposite meanings (when modelOpen.value === isCollapsed.value they are out
of sync), so the check isCollapsed.value === v is intentional and collapse(!v)
flips the UI to sync them; keep the existing guards (isMobile, canCollapse) and
reference the watch, modelOpen, isMobile, canCollapse, isCollapsed, and collapse
symbols in the comment so future readers understand the non‑obvious boolean
inversion.
- Around line 388-391: The template currently conditionally calls handlers with
ternaries (e.g., `@mousedown`="isResizable ? handleMouseDown($event) : undefined")
which still evaluates the call expression; replace these with short-circuit
bindings so the handler function reference is only used when isResizable is
true: change `@mousedown`, `@touchstart`, and `@dblclick` to use expressions like
`@mousedown`="isResizable && handleMouseDown", `@touchstart`="isResizable &&
handleTouchStart", `@dblclick`="isResizable && handleDoubleClick" (leave
`@click`="onRailClick" as-is); this uses isResizable, handleMouseDown,
handleTouchStart, and handleDoubleClick to avoid unnecessary call-site
preparation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 58d6f574-ae1b-4d1f-9690-14a462550597

📥 Commits

Reviewing files that changed from the base of the PR and between 4427824 and 25fdc5d.

⛔ Files ignored due to path filters (2)
  • test/components/__snapshots__/Sidebar-vue.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/Sidebar.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • docs/app/components/content/examples/sidebar/SidebarExample.vue
  • docs/content/docs/2.components/dashboard-sidebar.md
  • docs/content/docs/2.components/sidebar.md
  • src/runtime/components/Sidebar.vue
  • src/theme/sidebar.ts

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 12, 2026

npm i https://pkg.pr.new/@nuxt/ui@6340

commit: a8c6967

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant