Extends
The extends feature allows you to inherit tokens from base token files, making it easy to share design tokens across multiple projects.
What is extends?
extends lets you reference one or more base token files in your configuration. These base tokens are merged with your project’s tokens, giving you a foundation to build upon.
This is useful for:
- Sharing design systems across multiple projects
- Creating token libraries that can be versioned and distributed
- Maintaining consistency across related applications
- Layering design decisions - foundation → brand → project
Basic usage
Extending from a single file
To extend from a base token file, add the extends field to your ngcorex.config.ts:
import { defineConfig } from "@ngcorex/css";
export default defineConfig({
extends: "./base-tokens.json",
tokens: {
// Your project-specific tokens
},
});Extending from multiple files
You can extend from multiple base files:
import { defineConfig } from "@ngcorex/css";
export default defineConfig({
extends: ["./foundation-tokens.json", "./brand-tokens.json"],
tokens: {
// Your project-specific tokens
},
});How extends works
Path resolution
Paths in extends are resolved relative to your ngcorex.config.ts file.
project/
├── ngcorex.config.ts
├── tokens/
│ ├── foundation-tokens.json
│ └── brand-tokens.json
└── src/Configuration:
export default defineConfig({
extends: ["./tokens/foundation-tokens.json", "./tokens/brand-tokens.json"],
});Merge order
Tokens are merged in this order:
- First base file
- Second base file
- …
- Your project’s tokens
Later sources override earlier ones.
Example:
// foundation-tokens.json
{
"spacing": {
"sm": "0.5rem",
"md": "1rem",
"lg": "1.5rem"
},
"colors": {
"primary": {
"500": "#2563eb"
}
}
}// brand-tokens.json
{
"colors": {
"primary": {
"500": "#3b82f6" // Overrides foundation's primary-500
},
"accent": {
"500": "#10b981"
}
}
}// ngcorex.config.ts
export default defineConfig({
extends: ["./foundation-tokens.json", "./brand-tokens.json"],
tokens: {
colors: {
primary: {
900: "#1e3a8a", // Adds to primary palette
},
},
},
});Result:
{
"spacing": {
"sm": "0.5rem",
"md": "1rem",
"lg": "1.5rem"
},
"colors": {
"primary": {
"500": "#3b82f6", // From brand (overrode foundation)
"900": "#1e3a8a" // From project tokens
},
"accent": {
"500": "#10b981" // From brand
}
}
}Deep merge
ngCorex uses a deep merge strategy, meaning nested objects are merged intelligently:
// base-tokens.json
{
"colors": {
"primary": {
"100": "#dbeafe",
"500": "#3b82f6",
"900": "#1e3a8a"
}
}
}// Your project tokens
{
"colors": {
"primary": {
"500": "#2563eb" // Only overrides this value
}
}
}Result:
{
"colors": {
"primary": {
"100": "#dbeafe", // Preserved from base
"500": "#2563eb", // Overridden
"900": "#1e3a8a" // Preserved from base
}
}
}Use cases
Shared design system
Create a shared design system package:
@my-company/design-tokens/
├── package.json
├── foundation.json
├── brand-a.json
└── brand-b.jsonInstall in multiple projects:
npm install @my-company/design-tokensUse in project:
// project-a/ngcorex.config.ts
import { defineConfig } from "@ngcorex/css";
export default defineConfig({
extends: [
"@my-company/design-tokens/foundation.json",
"@my-company/design-tokens/brand-a.json",
],
});// project-b/ngcorex.config.ts
import { defineConfig } from "@ngcorex/css";
export default defineConfig({
extends: [
"@my-company/design-tokens/foundation.json",
"@my-company/design-tokens/brand-b.json",
],
});Layered design decisions
Organize tokens by layer:
// foundation-tokens.json
{
"spacing": {
/* base scale */
},
"colors": {
"neutral": {
/* neutral palette */
}
}
}// brand-tokens.json
{
"colors": {
"primary": {
/* brand colors */
}
}
}// project-tokens.json
{
"colors": {
"primary": {
/* project overrides */
}
}
}Environment-specific tokens
Use extends with environment variables:
import { defineConfig } from "@ngcorex/css";
const brand = process.env.BRAND || "default";
export default defineConfig({
extends: `./tokens/${brand}-tokens.json`,
});Best practices
- Keep base files focused - Each base file should have a clear purpose
- Document your layers - Make it clear what each base file provides
- Version your base files - Track changes as your design evolves
- Use semantic naming - Make it obvious what each file contains
- Avoid circular dependencies - Don’t have files that extend from each other
Limitations
- Only JSON files are supported - You cannot extend from
ngcorex.config.tsfiles - Paths are relative to config - All paths are resolved from
ngcorex.config.tslocation - No circular references - A file cannot extend from itself or create circular dependencies
Common patterns
Foundation + Brand pattern
export default defineConfig({
extends: [
"./tokens/foundation.json", // Base design system
"./tokens/brand.json", // Brand-specific tokens
],
});Foundation + Brand + Project pattern
export default defineConfig({
extends: [
"./tokens/foundation.json", // Base design system
"./tokens/brand.json", // Brand-specific tokens
],
tokens: {
// Project-specific overrides
},
});Multi-brand pattern
const brand = process.env.BRAND || "default";
export default defineConfig({
extends: ["./tokens/foundation.json", `./tokens/brands/${brand}.json`],
});Next steps
To learn more:
- Design Tokens - understanding token structure
- Presets - using pre-configured token sets
- Configuration - configuring extends in ngcorex.config.ts