Strongtie Design System
Getting StartedComponents

Search documentation

Search for a command to run or a page to navigate to.

Getting Started
  • Introduction
  • Package Installation
  • Styles Only (CSS)
  • Code Quality Setup
  • Resources
Guides
  • Design Systems at Simpson
  • Framework Recommendations
  • Design Standards
  • Design Standards Examples
AI-Assisted Development
  • AI Agent Guide
  • AI Agent Skills
  • AGENTS.md Template
Registry
  • Getting Started
  • Complete Catalog
  • Button
  • Form
  • Dialog
  • Sidebar
  • Chart
  • Combobox
  • Datepicker
  • Multi Select
  • Tab Nav
  • Tree
Foundations
  • States
  • Variables
Migrations
  • shadcn → Package Codemod
  • Migration Guide
  • CDN Migration Guide
  • Telerik Migration
Governance
  • Governance Model
  • Contribution Model
Components
  • Accordion
  • Alert
  • Alert Dialog
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Date Picker
  • Dialog
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Form
  • Hover Card
  • Input
  • Input Group
  • Input Otp
  • Item
  • Kbd
  • Label
  • Menubar
  • Multi Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Tab Nav
  • Table
  • Tabs
  • Textarea
  • Toaster
  • Toggle
  • Toggle Group
  • Tooltip
  • Tree
2026 Simpson Strong-Tie

shadcn → Package Codemod

PreviousNext

Automatically migrate a shadcn/ui app to the @strongtie/design-system package. Rewrites imports, swaps dependencies, modularizes CSS, and flags anything it can't safely transform.

The @strongtie/design-system package is the recommended path for teams that want pre-built, versioned components without owning the primitive code. If you already have a shadcn/ui app with vendored @/components/ui/* primitives, the codemod migrates it to the package for you — rewriting imports, swapping dependencies, and modularizing your CSS in one pass.

This tool migrates you toward the package. It requires Azure Artifacts access; environments without feed credentials should use the public Strongtie registry for new component installs.

Overview

The codemod finds imports of your vendored shadcn primitives and points them at the published package instead. At a glance:

src/components/toolbar.tsx
- import { Button } from "@/components/ui/button"
- import { Card, CardContent } from "@/components/ui/card"
+ import { Button } from "@strongtie/design-system/button"
+ import { Card, CardContent } from "@strongtie/design-system/card"

In the same run it updates package.json, rewrites your CSS entry to the modular Tailwind imports, deletes the now-migrated ui/ primitives, and leaves // TODO markers on anything it can't safely convert.

Prerequisites

  • Node.js >= 20 and npm (yarn/pnpm/bun also work).
  • A project that currently imports vendored primitives via @/components/ui/* (the standard shadcn alias).
  • A clean git tree. The codemod edits files in place.

Commit or stash your work first. A live run rewrites files on disk. The tool refuses to run on a dirty git tree unless you pass --yes (or run with --dry, which writes nothing), so committing first is both a safety net and the smoothest path.

What it does

  • Rewrites @/components/ui/* imports (and relative ui/* imports and re-exports) to @strongtie/design-system/*.
  • Adds @strongtie/design-system to your dependencies — or to peerDependencies if your package.json looks like a publishable library.
  • Prunes shadcn primitive dependencies that are now unused, while keeping runtime peers like sonner and lucide-react.
  • Raises a kept runtime peer that sits below the package's peer floor up to the required range (e.g. sonner to ^2.0.5, tw-animate-css to ^1.4.0), so npm install doesn't fail with a peer-dependency (ERESOLVE) conflict. A peer already at or above the floor — or pinned to a non-semver value like latest or a tarball URL — is left untouched.
  • Rewrites your CSS entry to modular Tailwind imports (styles/tokens + tailwindcss + styles/theme + styles/scan), removing the duplicated shadcn token ramp while preserving your app-specific tokens.
  • Classifies TabNav usage: converts clearly state-only usages to Tabs / TabsList variant="line" under --tab-nav convert, and flags route-driven usages.
  • Renames platform-shell's CollapsibleItem alias to Collapsible, fixes the import, and leaves a // TODO for you to verify.
  • Deletes the migrated ui/ primitives while keeping your custom composites and lib/utils.ts.

What it does NOT do

  • Non-@/ aliases are not auto-detected. Only the @/components/ui/* alias form and relative ui/* forms are rewritten. If your project uses a different alias, those imports are left untouched (see Troubleshooting).
  • Does not migrate a @base-ui/react-based combobox. If your local ui/combobox.tsx is built on @base-ui/react, the package combobox is API-incompatible, so yours is kept and marked with a // TODO. A plain shadcn combobox is rewritten normally.
  • Does not force route-driven TabNav off the deprecated tab-nav. Route-driven usage is kept and flagged with a // TODO.
  • Keeps custom composites (confirm-dialog, etc.) — anything that isn't a plain vendored primitive stays in your project.
  • Never writes a PAT or secret to any file.

Usage

Run the migration against your source directory:

npx @strongtie/design-system-codemod@latest migrate ./src

The default command is migrate, so npx @strongtie/design-system-codemod@latest ./src works too.

Projects whose @/ alias maps to the repo root (rather than src/) spread their imports across the whole tree, so scoping to ./src would miss most of them. Point the codemod at the root instead — migrate . is supported. If the repo keeps sibling copies of the app in-tree (vendored snapshots, nested git worktrees, an agent's .claude/worktrees), exclude each one so it stays out of every scan: migrate . --ignore-pattern archived-contexts --ignore-pattern .claude.

Pass a real path. If you point the codemod at a directory with no matching files, it reports 0 files and prints a "check your path" hint rather than failing silently. If you see 0 files, double-check the path.

Flags reference

FlagApplies toDescription
--dryglobalPreview only — writes nothing. Exempt from the clean-git-tree guard.
--printglobalPrint the changed file contents to stdout (works with or without --dry).
--yesglobalSkip prompts and the clean-git-tree guard.
--verboseglobalPer-file and per-dependency change detail.
--extensions <list>globalFile extensions to scan. Default: tsx,ts,jsx,js.
--ignore-pattern <glob>globalGlob of paths to skip. Repeatable — pass the flag more than once to skip several. Applies to every scan (rewrite, deletion, and dependency), so excluding a vendored app copy or a nested git worktree keeps it out of all of them.
--no-cssmigrateSkip the CSS transform.
--no-depsmigrateSkip the dependency transform.
--no-delete-uimigrateKeep the vendored ui/ primitives instead of deleting them.
--tab-nav <mode>migrateflag (default, conservative — keep on tab-nav + TODO) or convert (convert state-only usages to Tabs / TabsList variant="line").
--globalsetup-registryWrite ~/.npmrc instead of the project .npmrc.

Recommended workflow

Commit or stash

Start from a clean git tree so you can diff and roll back:

git status

Preview with a dry run

See exactly what would change without writing anything:

npx @strongtie/design-system-codemod@latest migrate ./src --dry --print

Review the preview

Read the printed diffs and the list of files the codemod would touch. Confirm the import rewrites, dependency changes, and CSS rewrite look right.

Run it for real

npx @strongtie/design-system-codemod@latest migrate ./src

Diff and resolve TODOs

Review the changes and address every marker the codemod left behind:

git diff

Search for // TODO: @strongtie/design-system-codemod and resolve each one (combobox, route-driven TabNav, CollapsibleItem, etc.).

Build and test

npm run build

Commit

Once the build and tests pass, commit the migration as its own change.

Before/after examples

Import rewrite

src/components/dashboard.tsx
- import { Button } from "@/components/ui/button"
- import { Input } from "@/components/ui/input"
+ import { Button } from "@strongtie/design-system/button"
+ import { Input } from "@strongtie/design-system/input"

Dependency swap

package.json
  "dependencies": {
+   "@strongtie/design-system": "latest",
-   "@radix-ui/react-dialog": "^1.1.0",
-   "@radix-ui/react-slot": "^1.1.0",
-   "class-variance-authority": "^0.7.0",
    "lucide-react": "^0.400.0",
    "sonner": "^1.5.0"
  }

The codemod adds @strongtie/design-system as "latest" — review and pin the version after installing. Radix primitives, class-variance-authority, and other shadcn-only dependencies are removed only when nothing outside the deleted ui/ layer still imports them; sonner and lucide-react are always kept.

CSS rewrite

src/index.css
+ @import "@strongtie/design-system/styles/tokens";
  @import "tailwindcss";
+ @import "@strongtie/design-system/styles/theme";
  @import "tw-animate-css";
+ @import "@strongtie/design-system/styles/scan";
 
  :root {
-   --background: oklch(1 0 0);
-   --foreground: oklch(0.145 0 0);
    --brand: oklch(0.62 0.21 259); /* your app-specific tokens are preserved */
  }

Only the duplicated shadcn token ramp is removed; your app-specific tokens stay in place. A ramp token whose value differs from the design-system default (a deliberate override, e.g. a custom --primary) is also kept in place and flagged with a TODO, rather than silently dropped — percentage/degree spellings (oklch(100% 0 0deg)) are compared equal to their decimal form (oklch(1 0 0)), so only genuine overrides are preserved. The @strongtie/design-system/styles/scan import registers the package's compiled components for Tailwind scanning. On older package versions that predate that export, the codemod falls back to a relative @source "../node_modules/@strongtie/design-system/dist"; line instead.

Idempotency

The codemod is safe to re-run. A second pass over an already-migrated project is a no-op: nothing is rewritten and no new markers are added.

Manual follow-up

After the codemod finishes, a few steps are yours to complete:

  1. Install the package. The codemod updates package.json but doesn't run npm install. Configure Azure Artifacts and install — the setup-registry command below scaffolds the .npmrc for you, then follow the Package Installation guide.

  2. Resolve every // TODO marker. Search for // TODO: @strongtie/design-system-codemod and address each one.

  3. Type-check the project.

    npx tsc --noEmit
  4. Verify the combobox and TabNav. These are intentionally left in place — confirm the local combobox still works and decide how to handle any route-driven TabNav.

setup-registry

The package is published to the Azure Artifacts Simpson feed, so npm needs a scoped registry entry. The setup-registry command writes that .npmrc for you:

npx @strongtie/design-system-codemod@latest setup-registry

Pass --global to write ~/.npmrc instead of the project .npmrc. This command scaffolds the scoped registry configuration only — it never writes a PAT or secret. Complete authentication by following the Azure Artifacts npm guide, covered in the Package Installation guide.

Troubleshooting

0 files found

The codemod scanned your path and matched nothing. Confirm you passed the directory that contains your components (usually ./src), and that your files use the extensions it scans (tsx,ts,jsx,js by default — override with --extensions).

Imports weren't rewritten

The codemod only rewrites the @/components/ui/* alias form and relative ui/* forms. If your project uses a different alias (for example ~/components/ui/*), those imports are not auto-detected. Rewrite them manually, or temporarily normalize your alias to @/ before running.

TypeScript errors after migration

Some package components have a slightly different API than the vendored primitives (API drift). Run npx tsc --noEmit to surface these and adjust the call sites. A @base-ui/react-based combobox in particular is intentionally left local because that package version is API-incompatible; a plain shadcn combobox is migrated normally.

Sidebar overlaps a full-width top bar

If your app renders a full-width header above the sidebar (rather than the standard shadcn shell where the header sits inside the content, to the right of a full-height sidebar), the package sidebar — which is fixed and anchored to the viewport top — will overlap that header, hiding anything on its left (e.g. a logo) and drawing a seam across it. Tell the sidebar how tall your top bar is by setting --header-height on the SidebarProvider; the fixed sidebar then starts below the bar. It defaults to 0px, so the standard shell is unaffected.

<SidebarProvider style={{ "--header-height": "3.5rem" } as React.CSSProperties}>

Missing utility classes / unstyled components

If package components render unstyled, your Tailwind build isn't scanning the package dist. Confirm the CSS rewrite added @import "@strongtie/design-system/styles/scan"; (or, on older package versions, the fallback @source ".../node_modules/@strongtie/design-system/dist";). See Using with Tailwind CSS.

Azure authentication (E401)

Installing the package requires access to the Simpson feed. Run setup-registry to scaffold the scoped .npmrc, then complete PAT authentication as described in the Package Installation guide.

Related

  • Package Installation — configure Azure Artifacts and install the package.
  • Migration Guide — migrating from the deprecated @studs/react package.
  • Components — browse everything the package provides.
CDN Migration GuideContribution Model

On This Page

OverviewPrerequisitesWhat it doesWhat it does NOT doUsageFlags referenceRecommended workflowBefore/after examplesImport rewriteDependency swapCSS rewriteIdempotencyManual follow-upsetup-registryTroubleshooting0 files foundImports weren't rewrittenTypeScript errors after migrationSidebar overlaps a full-width top barMissing utility classes / unstyled componentsAzure authentication (E401)Related

Contribute

  • Report an issue
  • Request a feature
  • Edit this page