This project is a Bun-managed Next.js 16 + React 19 + Tailwind v4 shadcn/ui app with a local fork of the official sidebar. The fork adds drag-to-resize behavior, so sidebar changes must be reviewed manually and kept separate from broad dependency or codemod work.
- Use Bun only:
bun install,bun add,bun remove,bun update, andbunx. - Do not create
package-lock.json,pnpm-lock.yaml, oryarn.lock. - Keep each phase independently revertible.
- Commit messages must be English Conventional Commits.
- Do not run
bunx shadcn@latest add sidebaragainst this repository. - Treat
components/ui/sidebar.tsxandhooks/use-sidebar-resize.tsas the core fork. Any codemod touching them requires manual diff review. - Preserve the existing sidebar cookies:
sidebar:stateandsidebar:width. - Preserve server-side cookie seeding in
components/providers/index.tsx.
- Keep the current tooltip colors for this upgrade. Do not adopt the upstream
bg-foreground text-backgroundtooltip colors in phase 3. - Defer Next.js 16 until phase 5. If phase 5 runs, keep
unstable_cacheby default unless current Next.js 16 docs or validation require a migration. - Defer the resize hook rewrite until phases 0-4 have been completed and reviewed.
- Defer TypeScript 6, ESLint 10, and
lucide-react1.x until after the main upgrade path is stable. - Phase 2 may align Next.js 15 patch versions when keeping
nextandeslint-config-nexton the same 15.3.x line.
- Created branch:
codex/upgrade-2026-06. - Confirmed package manager state: Bun 1.3.1, Node v24.14.0, and only
bun.lockbexists. - Ran
bun install.- Result: succeeded and installed 364 packages.
- Note: Bun rewrote
bun.lockb; this will be carried with dependency changes in a later phase rather than committed as a standalone baseline change.
- Ran
bun run build.- Result: exited 0 and generated the production build.
- Baseline warning: Next.js reported an ESLint rule-load failure while building:
@typescript-eslint/no-unused-expressionscould not readallowShortCircuit. - Baseline warning:
metadataBaseis not set for Open Graph/Twitter image resolution.
- Ran
bun run lint.- Result: failed with the same
@typescript-eslint/no-unused-expressionsrule-load error inapp/actions/github.ts.
- Result: failed with the same
- Started dev server at
http://localhost:3000. - Ran Agent Browser smoke checks.
- Page identity: title
shadcn-resizable-sidebar, URLhttp://localhost:3000/. - Initial desktop render: sidebar and sample content were visible.
- Click collapse: passed;
data-statechanged tocollapsedandsidebar:state=falsewas written. - Keyboard shortcut: passed with
Control+b; sidebar returned toexpandedandsidebar:state=truewas written. - Drag resize: passed; width changed from
16remto20.6rem, andsidebar:width=20.6remwas written. - Reload persistence: passed; server-rendered width restored to
20.6rem. - Theme state: passed;
next-themespersisted and restoredlightanddark. - Dropdown animation: failed as expected; computed animation was
none/0sdespiteanimate-inand related classes being present. - Tooltip animation: failed as expected; computed animation was
none/0s. - Mobile Sheet: opened at 390px width, but computed animation was
none/0s. - Mobile Sheet accessibility: failed as expected; Radix reported missing
DialogTitleand missing description warnings.
- Page identity: title
- Captured baseline screenshots under
/tmp/shadcn-resizable-sidebar-upgrade/phase0/.
- Fix the sidebar token alias in
app/globals.css. - Fix
transition-[margin,opa]to useopacity. - Remove invalid
hsl()wrapping around sidebar OKLCH tokens. - Add
tw-animate-cssand import it after@import "tailwindcss";. - Remove unused
@radix-ui/react-icons. - Re-run build and Agent Browser smoke checks.
bun run buildstill exits 0 with the known baseline ESLint rule-load warning andmetadataBasewarning.bun run lintstill fails with the known baseline@typescript-eslint/no-unused-expressionsrule-load error.- Dropdown, tooltip, and mobile Sheet animations now compute real
enteranimations instead ofnone/0s. - Desktop collapse, keyboard shortcut, drag resize, and width cookie behavior still pass.
- Mobile Sheet still reports missing title/description warnings; this remains scheduled for phase 3.
- Commit with
fix: repair sidebar tokens and animations.
- Keep Next.js on the 15.3.x line.
- Align
nextandeslint-config-nextto the same 15.3.x patch.- Updated both to
15.3.9.
- Updated both to
- Update Tailwind v4 packages within the v4 line.
- Updated
tailwindcssand@tailwindcss/postcssto^4.3.1.
- Updated
- Update
tailwind-mergewithin the v3 line.- Updated to
^3.6.0.
- Updated to
- Update
next-themeswithin the v0 line.- Updated to
^0.4.6.
- Updated to
- Refresh React 19 lockfile resolution without moving to a React major.
- Updated
reactandreact-domto^19.2.7.
- Updated
- Re-run build and Agent Browser smoke checks.
bun run buildpasses on Next.js 15.3.9 with the known baseline ESLint rule-load warning andmetadataBasewarning.bun run lintstill fails with the known baseline@typescript-eslint/no-unused-expressionsrule-load error.- Desktop render, persisted width, dropdown animation, drag resize, and mobile Sheet animation pass.
- Mobile Sheet title/description warnings remain scheduled for phase 3.
- Commit with
chore: align low-risk dependencies.
- Add accessible mobile Sheet title and description.
- Add upstream
data-slotattributes while preserving existingdata-sidebarattributes. - Change the sidebar trigger to
size-7andPanelLeftIcon. - Port the upstream
SidebarMenuSubItemwrapper. - Simplify
SidebarInsetto the upstreamw-full flex-1shape after validating layout. - Keep current tooltip colors.
- Only remove the custom
SidebarInputfocus ring if the current Input primitive provides an equivalent focus-visible ring.- Verified
components/ui/input.tsxprovidesfocus-visible:border-ring,focus-visible:ring-ring/50, andfocus-visible:ring-[3px].
- Verified
- Re-run build and Agent Browser smoke checks.
bun run buildpasses with the known baseline ESLint rule-load warning andmetadataBasewarning.bun run lintstill fails with the known baseline@typescript-eslint/no-unused-expressionsrule-load error.- Desktop
data-slotattributes were added while coredata-sidebarselectors remained present. - Mobile Sheet now includes an sr-only title and description, and Radix Dialog title/description console warnings are gone.
- Desktop keyboard toggle, drag resize, width cookie, and page console/errors pass.
- Commit with
refactor: align sidebar primitive fixes.
- Migrate Radix imports to the unified
radix-uipackage. - Manually review any diff touching
components/ui/sidebar.tsx.- The sidebar diff only changes primitive imports and
asChildslot plumbing. Resize state, cookies, drag rail behavior, and width constants are preserved.
- The sidebar diff only changes primitive imports and
- Convert
Slotusage after the unified package lands.- The shadcn migration uses
SlotPrimitive.Slotfromradix-ui.
- The shadcn migration uses
- Remove scattered
@radix-ui/react-*dependencies only after imports are migrated. - Re-run build and Agent Browser smoke checks.
bun run buildpasses with the known baseline ESLint rule-load warning andmetadataBasewarning.bun run lintstill fails with the known baseline@typescript-eslint/no-unused-expressionsrule-load error.- Desktop render, dropdown animation, keyboard toggle, drag resize, mobile Sheet animation, and mobile Sheet accessibility all pass.
- Page console and page errors are empty after smoke.
- Commit with
chore: migrate radix primitives.
- Re-check current Next.js 16 documentation before changing code.
- Official upgrade docs list
bunx @next/codemod@canary upgrade latest. next lintis removed in Next.js 16 and should be migrated to the ESLint CLI.unstable_cacheis replaced byuse cachein Next.js 16 documentation, but it is still documented as an API. This upgrade keeps the existingunstable_cachecall for GitHub stars rather than enablingcacheComponents.
- Official upgrade docs list
- Run the official upgrade codemod.
- Upgraded to Next.js
16.2.9. - Migrated
lintfromnext linttoeslint .. - Updated
eslint.config.mjsto directeslint-config-nextflat config imports. - Updated React type packages to the codemod-selected React 19 versions.
- Upgraded to Next.js
- Fix lint issues exposed by the Next.js 16 ESLint migration.
- Replaced render-time
Math.random()inSidebarMenuSkeletonwith a deterministicuseId()-based width. - Replaced
useIsMobileeffect state synchronization withuseSyncExternalStore.
- Replaced render-time
- Set
turbopack.rootinnext.config.ts.- This removes the Next.js 16 workspace-root warning caused by an unrelated
/Users/felix/package-lock.jsonabove the project.
- This removes the Next.js 16 workspace-root warning caused by an unrelated
- Re-run validation.
bun run lintpasses.bun run buildpasses on Next.js16.2.9; only the existingmetadataBasewarning remains.- Agent Browser smoke passes for desktop render, dropdown animation, drag resize, width cookie, mobile Sheet animation, and mobile Sheet accessibility.
- Commit with
chore: upgrade to next 16.
- Keep the existing public resize behavior.
defaultWidth,width,setWidth,isDraggingRail,setIsDraggingRail,SidebarRail,enableDrag,useSidebarResize,sidebar:state,sidebar:width,data-dragging,duration-0,MIN_SIDEBAR_WIDTH, andMAX_SIDEBAR_WIDTHremain in place.
- Move the drag hot path out of React context state.
- During drag,
useSidebarResizewrites--sidebar-widthdirectly to the sidebar wrapper element. - React state and
sidebar:widthcookie are committed on pointerup instead of every pointermove. - The hook keeps a backward-compatible
handleMouseDownreturn value for external consumers, whileSidebarRailnow usesonPointerDown.
- During drag,
- Switch the project path to Pointer Events.
SidebarRailusesonPointerDown.- The hook uses pointer id tracking,
setPointerCapture, pointer cancel handling, and temporarybody.style.userSelect = "none"during drag.
- Use modern ref composition.
- Replaced
mergeButtonRefswith RadixuseComposedRefs. - Deleted
lib/merge-button-refs.ts.
- Replaced
- Remove dead resize refs.
- Removed the unused
lastWidth,lastLoggedWidth,dragOffset,lastToggleWidth, anddragStartPointbookkeeping.
- Removed the unused
- Clamp seeded widths before storing them in React state.
- Cookie-provided
defaultWidthis clamped to the 14rem-22rem sidebar bounds before it becomes provider state.
- Cookie-provided
- Re-run validation.
bun run lintpasses.bun run buildpasses on Next.js16.2.9; only the existingmetadataBasewarning remains.- Agent Browser smoke passes for desktop drag resize, drag-time DOM width updates, pointerup cookie commit, max-width clamp, reload persistence, click collapse, keyboard expand, drag-to-collapse, drag-to-expand, mobile Sheet animation, and mobile Sheet accessibility.
- Focused React render recording across a continuous drag showed
SidebarProviderre-rendered twice rather than once per pointer move. - Screenshots were captured under
/tmp/shadcn-resizable-sidebar-upgrade/phase6/.
- Commit with
refactor: modernize sidebar resize handling.
- Phase 7: TypeScript 6, ESLint 10, and
lucide-react1.x after the main upgrade is stable.