Skip to content

chore(deps): upgrade tailwind-merge to v3 - #15

Merged
agentHits merged 3 commits into
AgentHits-Devfrom
chore/deps-tailwind-merge-3
Oct 7, 2026
Merged

agentHits merged 3 commits into
AgentHits-Devfrom
chore/deps-tailwind-merge-3

Conversation

@agentHits

Copy link
Copy Markdown
Collaborator

What changed

  • tailwind-merge ^2.6.1 -> ^3.7.0 in apps/dokploy (the only workspace that uses it), plus bun.lock.
  • No code changes. cn in apps/dokploy/lib/utils.ts is a plain twMerge(clsx(inputs)), and there is no extendTailwindMerge / createTailwindMerge config anywhere. So none of the config-level breaking changes apply: theme scale keys, the removed isLength, prefix format, orderSensitiveModifiers and custom separators.

Why

tailwind-merge 3 is the line built for Tailwind CSS v4, and we are on tailwindcss ^4.3.3. v2 targets Tailwind v3 and does not recognise v4 syntax such as w-(--var), outline-hidden, field-sizing-*, ring-3 or shadow-xs, so it left conflicting classes in place.

Release notes (2.6.1 -> 3.7.0)

  • 3.0.0: drops Tailwind v3 and adds Tailwind v4. The breaking changes are all at the config/API level (see the migration guide), plus classes that exist only in Tailwind v3 are no longer supported.
  • 3.1-3.6: support for Tailwind 4.1, 4.2 and 4.3 utilities, a new postfixLookupClassGroups option, readonly arrays.
  • 3.7.0: bug fixes: color()/light-dark() arbitrary values are classified as colors, max-h-none, px vs ps/pe, columns-auto, bg-conic, container sizes like inline-2xl.

Custom theme tokens

I checked styles/globals.css and shadcn/tailwind.css for @theme tokens that tailwind-merge would need to know about:

  • Colors (border, input, ring, background, primary, sidebar-* and so on): the default config handles these, because it treats any unknown text-* / bg-* / border-* value as a color.
  • Font sizes: there are no custom --text-* tokens. text-sm text-primary keeps both classes, and text-xs ... text-sm merges correctly. No config needed.
  • Containers 2xl/8xl/9xl/10xl, radius sm..4xl, breakpoint 3xl: these are t-shirt sizes, which the default validators recognise.
  • Animations caret-blink, accordion-down/up: neither v2 nor v3 knows them, but no cn call combines them with another animate-*, so adding them to the config would not change any output.

Before/after comparison

A throwaway script (not committed) collected class strings from components/, pages/, hooks/ and lib/:

  • every cn(...) call
  • every cva variant
  • every className literal
  • the base classes of each components/ui component, combined with the className passed at each of its call sites

It ran the same 10,060 class strings through v2.6.1 and v3.7.0. 17 of them give different output. In every one, v3 removes a class that v2 left in place, and that class had already lost in the CSS:

Pattern Cases Example v3 removes Visual effect
DropdownMenuContent base w-(--radix-dropdown-menu-trigger-width) + className w-56 / w-64 / w-80 / w-[200px] / w-[300px] 6 servers/actions/show-dokploy-actions.tsx w-(--radix-dropdown-menu-trigger-width) none. Tailwind v4 already put the caller's width later in the CSS, so it already won (checked by compiling with tailwindcss 4.3.3)
same base + w-[200px] max-h-[280px] 1 dashboard/projects/show.tsx the w-(--radix-...) and max-h-(--radix-...) defaults none, same reason
TabsContent base outline-none + className="outline-hidden" 5 servers/setup-server.tsx outline-none none in normal mode. In forced-colors mode, outline-hidden now shows its intended outline
Textarea base field-sizing-content + className="field-sizing-fixed" 2 certificates/handle-certificate.tsx field-sizing-content none, field-sizing-fixed already won in the CSS
duplicate w-(--radix-dropdown-menu-trigger-width) 1 layouts/user-nav.tsx the duplicate none
both ternary branches joined 2 ui/sidebar.tsx:217,229 n/a artifact of the script: the two branches never apply together at runtime

Verification

  • bun install --frozen-lockfile: clean.
  • bun run typecheck: all 4 workspaces pass.
  • bunx biome check on the changed files: clean.
  • bun run test (apps/dokploy): 2053 of 2079 tests pass. The failures are timeouts in server-side tests (better-auth-schema-compat, db-backup-restore-injection, cloud-queue-availability, env-file-literals, remote-stream) and the Docker-backed application.real.test.ts. The machine was running several suites in parallel, and the set of failing tests changed between two runs. None of these tests import UI code or tailwind-merge (no test does), so the failures are unrelated to this bump.
  • I did not run next build locally; CI builds it.

Manual check on dev

  • Open a few dropdowns with a custom width (server actions menu, project environment selector, the user menu in the sidebar) and check their width.
  • Tabs in the server setup dialog, including keyboard focus on the tab content.
  • The textareas in the certificate form: fixed height, scrollable.
  • A general pass over buttons, inputs and the collapsible sidebar, since every cn call now goes through the new merge logic.

🤖 Generated with Claude Code

agentHits and others added 3 commits October 6, 2026 16:45
tailwind-merge 3 is the line that understands Tailwind CSS v4 classes
(`w-(--var)`, `outline-hidden`, `field-sizing-*`, `ring-3`, ...). The
project has no custom tailwind-merge config and no custom font-size
tokens, so `cn` keeps using the default `twMerge`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@agentHits
agentHits merged commit 0d08a6c into AgentHits-Dev Oct 7, 2026
8 checks passed
@agentHits
agentHits deleted the chore/deps-tailwind-merge-3 branch October 7, 2026 04:51
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