Code transformation pipeline for framework compatibility and customization. Transformers modify component source code to match project configuration, handling imports, styles, icons, React Server Components, and more.
Transforms styles with CSS variable substitution and theme mapping. Converts style names to their CSS variable equivalents based on configuration using configurable transformers.
/**
* Transform styles with CSS variable substitution
* @param source - Source component code
* @param options - Transform options including style map and optional transformers
* @returns Promise resolving to transformed component code
*/
function transformStyle(
source: string,
options: {
styleMap: StyleMap
transformers?: TransformerStyle<SourceFile>[]
}
): Promise<string>Parameters:
source: string - Source component code to transform. Required.options.styleMap: StyleMap - Map of style names to CSS variable definitions. Required.options.transformers?: TransformerStyle<SourceFile>[] - Optional array of style transformers (defaults to [transformStyleMap]). Each transformer receives a SourceFile and styleMap.Returns: Promise<string> - Transformed component code as a string.
Usage Example:
import { transformStyle, createStyleMap } from 'shadcn/utils';
// Create style map from base styles
const styleMap = createStyleMap(`
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
}
`);
// Transform component styles
const source = `
export function Button() {
return (
<button className="bg-primary text-foreground">
Click me
</button>
);
}
`;
const transformed = await transformStyle(source, {
styleMap
});
// With custom transformers
const transformed = await transformStyle(source, {
styleMap,
transformers: [customTransformer, transformStyleMap]
});Note: This is a string-to-string transformation. For AST-based transformations, use the individual transformer functions.
Creates a style map from CSS input. Parses CSS and builds a map for style transformations.
/**
* Create style map from CSS
* @param input - CSS input string
* @returns StyleMap for use in transformations
*/
function createStyleMap(input: string): StyleMapParameters:
input: string - CSS input to parse. Should contain CSS variable definitions in :root or similar selectors.Returns: StyleMap - Map of style names to CSS variable definitions:
type StyleMap = Record<string, string>
// Example: { "background": "0 0% 100%", "foreground": "222.2 84% 4.9%" }Usage Example:
import { createStyleMap } from 'shadcn/utils';
const css = `
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
}
`;
const styleMap = createStyleMap(css);
// Use styleMap in transformStyle callsTransforms icon imports between icon libraries. Converts icon imports and usage from one library to another (e.g., lucide to phosphor). This transformer modifies the Abstract Syntax Tree (AST) using ts-morph and returns the modified SourceFile object.
/**
* Transform icon imports between libraries
* @param opts - Transform options with config and sourceFile
* @returns Promise resolving to transformed SourceFile AST
*/
const transformIcons: TransformerType: Transformer - A transformer function that operates on ts-morph SourceFile ASTs
Parameters:
opts: TransformOpts & { sourceFile: SourceFile } - Options including:
filename: string - Component filename. Required.raw: string - Raw source code. Required.config: Config - Configuration with iconLibrary property. Required.sourceFile: SourceFile - ts-morph SourceFile AST to transform. Required.Returns: Promise<SourceFile> - Transformed SourceFile AST (call .getText() to get string)
Usage Example:
import { transformIcons } from 'shadcn/utils';
import { Project, ScriptKind } from 'ts-morph';
const source = `
import { ChevronRight, Check } from 'lucide-react';
export function Component() {
return (
<div>
<ChevronRight />
<Check />
</div>
);
}
`;
// Create a SourceFile AST using ts-morph
const project = new Project();
const sourceFile = project.createSourceFile('component.tsx', source, {
scriptKind: ScriptKind.TSX
});
// Transform the SourceFile
await transformIcons({
filename: 'component.tsx',
raw: source,
config: {
iconLibrary: 'phosphor',
// ...other config
},
sourceFile: sourceFile
});
// Extract the transformed code
const transformedCode = sourceFile.getText();
// Result transforms imports to @phosphor-icons/react
// and updates usage to match phosphor patternsSupported Icon Libraries:
lucide - Lucide React (lucide-react)tabler - Tabler Icons (@tabler/icons-react)hugeicons - HugeIcons (@hugeicons/react, @hugeicons/core-free-icons)phosphor - Phosphor Icons (@phosphor-icons/react)Note: These transformers work directly on ts-morph SourceFile ASTs, not raw strings. For complete string-to-string transformations with multiple transformers, the shadcn CLI uses an internal transform function that chains these transformers together.
Transforms menu components for different styles and configurations. Adjusts menu component structure based on menuColor and menuAccent settings. This transformer modifies the Abstract Syntax Tree (AST) using ts-morph and returns the modified SourceFile object.
/**
* Transform menu components
* @param opts - Transform options with config and sourceFile
* @returns Promise resolving to transformed SourceFile AST
*/
const transformMenu: TransformerType: Transformer - A transformer function that operates on ts-morph SourceFile ASTs
Parameters:
opts: TransformOpts & { sourceFile: SourceFile } - Options including:
filename: string - Component filename. Required.raw: string - Raw source code. Required.config: Config - Configuration with menu-related properties (menuColor, menuAccent). Required.sourceFile: SourceFile - ts-morph SourceFile AST to transform. Required.Returns: Promise<SourceFile> - Transformed SourceFile AST (call .getText() to get string)
Usage Example:
import { transformMenu } from 'shadcn/utils';
import { Project, ScriptKind } from 'ts-morph';
const menuCode = `
export function Menu() {
return (
<nav>
<MenuItem>Home</MenuItem>
<MenuItem>About</MenuItem>
</nav>
);
}
`;
// Create a SourceFile AST using ts-morph
const project = new Project();
const sourceFile = project.createSourceFile('menu.tsx', menuCode, {
scriptKind: ScriptKind.TSX
});
// Transform the SourceFile
await transformMenu({
filename: 'menu.tsx',
raw: menuCode,
config: {
menuColor: 'inverted',
menuAccent: 'bold',
// ...other config
},
sourceFile: sourceFile
});
// Extract the transformed code
const transformedCode = sourceFile.getText();Configuration Options:
menuColor: "default" | "inverted" - Menu color schememenuAccent: "subtle" | "bold" - Menu accent styleTransforms render functions for framework compatibility. Adjusts render patterns for different React configurations. This transformer modifies the Abstract Syntax Tree (AST) using ts-morph and returns the modified SourceFile object.
/**
* Transform render functions
* @param opts - Transform options with config and sourceFile
* @returns Promise resolving to transformed SourceFile AST
*/
const transformRender: TransformerType: Transformer - A transformer function that operates on ts-morph SourceFile ASTs
Parameters:
opts: TransformOpts & { sourceFile: SourceFile } - Options including:
filename: string - Component filename. Required.raw: string - Raw source code. Required.config: Config - Configuration object. Required.sourceFile: SourceFile - ts-morph SourceFile AST to transform. Required.Returns: Promise<SourceFile> - Transformed SourceFile AST (call .getText() to get string)
Usage Example:
import { transformRender } from 'shadcn/utils';
import { Project, ScriptKind } from 'ts-morph';
const sourceCode = `
export function Component() {
return <div>Hello</div>;
}
`;
// Create a SourceFile AST using ts-morph
const project = new Project();
const sourceFile = project.createSourceFile('component.tsx', sourceCode, {
scriptKind: ScriptKind.TSX
});
// Transform the SourceFile
await transformRender({
filename: 'component.tsx',
raw: sourceCode,
config: myConfig,
sourceFile: sourceFile
});
// Extract the transformed code
const transformedCode = sourceFile.getText();Note: The following transformers are used internally by the shadcn CLI and are NOT exported from the shadcn/utils entry point. They are documented here for reference and understanding of the transformation pipeline, but cannot be directly imported unless you use internal paths (not recommended). For public API usage, use the exported functions above (transformStyle, transformIcons, transformMenu, transformRender, createStyleMap).
Applies multiple transformers to source code. Chains transformers in sequence.
/**
* Apply multiple transformers to source code
* @param opts - Transform options
* @param transformers - Optional array of transformer functions
* @returns Promise resolving to transformed code
*/
function transform(
opts: TransformOpts,
transformers?: Transformer<any>[]
): Promise<string>Note: Not available via public API. Used internally by the CLI.
Transform Order (when using default transformers):
transformImport - Updates import pathstransformRsc - Adds "use client" if neededtransformCssVars - Converts CSS variablestransformTwPrefixes - Adds Tailwind prefixtransformIcons - Converts icon importstransformMenu - Adjusts menu componentstransformAsChild - Handles asChild proptransformJsx - Converts to JavaScript if neededTransforms import statements to match project alias configuration. Updates import paths based on configured aliases.
/**
* Transform import statements
* @param opts - Transform options with config
* @returns Promise resolving to transformed code
*/
function transformImport(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to transform import paths based on configured aliases.
What it does:
@/components)config.aliases settingsTransforms code for React Server Components compatibility. Adds "use client" directive when needed.
/**
* Transform for React Server Components
* @param opts - Transform options with config
* @returns Promise resolving to transformed code
*/
function transformRsc(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to add "use client" directive when components use hooks or browser APIs.
What it does:
"use client" directive at top of file when neededconfig.rsc is trueTransforms CSS variables to match theme configuration. Converts CSS variable references based on baseColor and cssVariables settings.
/**
* Transform CSS variables
* @param opts - Transform options with config and baseColor
* @returns Promise resolving to transformed code
*/
function transformCssVars(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to transform CSS variable references based on baseColor and cssVariables settings.
What it does:
baseColorconfig.tailwind.cssVariables is trueTransforms Tailwind CSS prefixes. Adds configured prefix to Tailwind utility classes.
/**
* Transform Tailwind CSS prefixes
* @param opts - Transform options with config
* @returns Promise resolving to transformed code
*/
function transformTwPrefixes(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to add configured prefix to Tailwind utility classes.
What it does:
tw- prefix)config.tailwind.prefix is setTransforms asChild prop pattern. Converts asChild prop usage to match configuration.
/**
* Transform asChild prop usage
* @param opts - Transform options with config
* @returns Promise resolving to transformed code
*/
function transformAsChild(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to handle asChild prop pattern transformations.
Transforms JSX to JavaScript when tsx is false. Converts TypeScript React code to plain JavaScript.
/**
* Transform JSX to JavaScript
* @param opts - Transform options with config
* @returns Promise resolving to transformed code
*/
function transformJsx(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to convert TypeScript code to JavaScript when tsx is false.
What it does:
.tsx syntax to .jsxconfig.tsx is falseTransforms legacy icon usage patterns. Updates old icon patterns to current standards.
/**
* Transform legacy icon usage
* @param opts - Transform options with config
* @returns Promise resolving to transformed code
*/
function transformLegacyIcons(opts: TransformOpts): Promise<string>Note: Not available via public API. Used internally by the CLI to handle legacy icon import patterns.
// Transform options type (internal use - not exported)
type TransformOpts = {
filename: string
raw: string
config: Config
baseColor?: RegistryBaseColor
transformJsx?: boolean
isRemote?: boolean
}
// Transformer type (exported from shadcn/utils)
// Used by transformIcons, transformMenu, transformRender
type Transformer<Output = SourceFile> = (
opts: TransformOpts & {
sourceFile: SourceFile
}
) => Promise<Output>
// Style transformer type (not re-exported from shadcn/utils)
// Available for custom transformers, but accessed via direct import from styles/transform
type TransformerStyle<Output = SourceFile> = (opts: {
sourceFile: SourceFile
styleMap: StyleMap
}) => Promise<Output>
// Style map type
type StyleMap = Record<string, string>
// Note: SourceFile is from the 'ts-morph' package, an external dependency
// used for Abstract Syntax Tree manipulation during transformationsThe typical transformation pipeline for adding a component:
Note: The complete transformation pipeline uses internal transformers that are not available through the public API. The exported transformers (transformStyle, transformIcons, transformMenu, transformRender) can be used individually:
import {
transformStyle,
transformIcons,
transformMenu,
transformRender,
createStyleMap
} from 'shadcn/utils';
import { Project, ScriptKind } from 'ts-morph';
// Example: Transform styles (string-to-string)
const styleMap = createStyleMap(cssInput);
const styledCode = await transformStyle(componentSource, { styleMap });
// Example: Transform icons (requires SourceFile)
const project = new Project();
const sourceFile = project.createSourceFile('button.tsx', componentSource, {
scriptKind: ScriptKind.TSX
});
await transformIcons({
filename: 'button.tsx',
raw: componentSource,
config: myConfig,
sourceFile: sourceFile
});
const iconTransformed = sourceFile.getText();
// Example: Transform menu (requires SourceFile)
const menuSourceFile = project.createSourceFile('menu.tsx', menuSource, {
scriptKind: ScriptKind.TSX
});
await transformMenu({
filename: 'menu.tsx',
raw: menuSource,
config: myConfig,
sourceFile: menuSourceFile
});
const menuTransformed = menuSourceFile.getText();
// Example: Transform render (requires SourceFile)
const componentSourceFile = project.createSourceFile('component.tsx', componentSource, {
scriptKind: ScriptKind.TSX
});
await transformRender({
filename: 'component.tsx',
raw: componentSource,
config: myConfig,
sourceFile: componentSourceFile
});
const renderTransformed = componentSourceFile.getText();You can create custom style transformers for use with transformStyle. Note that TransformerStyle type is not re-exported from shadcn/utils, so you would need to define the type inline or access internal exports:
import { transformStyle } from 'shadcn/utils';
import type { SourceFile } from 'ts-morph';
// Define transformer type inline (recommended for external use)
type StyleTransformer = (opts: {
sourceFile: SourceFile;
styleMap: Record<string, string>;
}) => Promise<SourceFile>;
// Custom style transformer
const customStyleTransformer: StyleTransformer = async ({ sourceFile, styleMap }) => {
// Perform custom transformation on the sourceFile
// using ts-morph APIs
return sourceFile;
};
// Use with transformStyle
const result = await transformStyle(source, {
styleMap,
transformers: [customStyleTransformer]
});import { transformIcons } from 'shadcn/utils';
import { Project, ScriptKind } from 'ts-morph';
async function transformComponentCode(
sourceCode: string,
config: Config
): Promise<string> {
const project = new Project();
const sourceFile = project.createSourceFile('component.tsx', sourceCode, {
scriptKind: ScriptKind.TSX
});
// Apply icon transformation
await transformIcons({
filename: 'component.tsx',
raw: sourceCode,
config,
sourceFile
});
return sourceFile.getText();
}import { transformStyle, createStyleMap } from 'shadcn/utils';
async function transformMultipleComponents(
components: Array<{ name: string; code: string }>,
cssVars: string
): Promise<Array<{ name: string; code: string }>> {
const styleMap = createStyleMap(cssVars);
return Promise.all(
components.map(async (component) => ({
...component,
code: await transformStyle(component.code, { styleMap })
}))
);
}