Migration from Stitches
A complete guide to migrating from Stitches to Stoop, including feature comparison and step-by-step instructions.
Why Migrate?
Stoop is designed as a modern, actively maintained replacement for Stitches with key improvements:
- Active maintenance - Stitches is no longer maintained (as of June 2023)
- CSS variables - Instant theme switching without recompiling CSS
- Built-in multi-theme support - Provider component and
useTheme()hook included - Full Next.js App Router support - React 18 Server Components compatibility
- Simpler API - No theme parameter needed for
getCssText()
Feature Comparison
| Feature | Stitches | Stoop | Migration Impact |
|---|---|---|---|
| Core API | createStitches | createStoop | Simple rename |
| Theme tokens | $token syntax | $token syntax | Same |
| Variants API | variants property (2nd param) | variants property (2nd param) | Same |
| Compound variants | Supported | Not supported | Breaking change |
| Theme system | Runtime values | CSS variables | Better (instant switching) |
| Multi-theme | Manual management | Built-in Provider | Better (easier) |
| SSR support | Yes | Yes | Same |
| Next.js App Router | Limited | Full support | Better |
| Runtime CSS generation | Yes | Yes | Same |
| Utility functions | Many built-ins | Flexible system | Same capabilities |
Key Differences
Theme System
Stitches: Theme tokens resolve to runtime values injected via JavaScript.
Stoop: Theme tokens resolve to CSS variables (var(--colors-primary)), enabling instant theme switching without recompiling CSS.
Multi-Theme Support
Stitches: Requires manual theme management with CSS class switching.
Stoop: Built-in multi-theme support via Provider component with automatic CSS variable switching.
Compound Variants
Stitches: Supports compound variants (combining multiple variant conditions).
Stoop: Does not currently support compound variants (planned for future release). Variants work independently, which is sufficient for most use cases. Achieve similar results using conditional css props or wrapper components.
Utility Functions
Stitches: Advanced utility function system with extensive built-in utilities.
Stoop: Flexible utility function system with the same capabilities. Create any custom utilities you need. Stitches provides more built-in utilities out of the box, but Stoop's utility system is equally powerful and flexible.
Migration Steps
Step 1: Install Stoop
npm uninstall @stitches/react npm install stoop
Step 2: Update Theme Configuration
Before (Stitches):
import { createStitches } from '@stitches/react';
const { styled, css, globalCss, keyframes, getCssText } = createStitches({
theme: {
colors: {
primary: '#0070f3',
secondary: '#7928ca',
background: '#ffffff',
text: '#000000',
},
space: {
small: '8px',
medium: '16px',
large: '24px',
},
},
media: {
bp1: '(min-width: 640px)',
bp2: '(min-width: 768px)',
},
utils: {
mx: (value) => ({
marginLeft: value,
marginRight: value,
}),
},
});
After (Stoop):
// stoop.theme.ts (or theme.ts) - REQUIRED CONVENTION
import { createStoop } from 'stoop';
// Define your themes
const lightTheme = {
colors: {
primary: '#0070f3',
secondary: '#7928ca',
background: '#ffffff',
text: '#000000',
},
space: {
small: '8px',
medium: '16px',
large: '24px',
},
};
const darkTheme = {
colors: {
primary: '#3291ff',
background: '#000000',
text: '#ffffff',
},
// Other scales (space, etc.) inherit from lightTheme
};
// Create Stoop instance at module level (required convention)
const stoop = createStoop({
theme: lightTheme, // Default theme
themes: {
light: lightTheme,
dark: darkTheme,
},
media: {
bp1: '(min-width: 640px)',
bp2: '(min-width: 768px)',
},
utils: {
mx: (value) => ({
marginLeft: value,
marginRight: value,
}),
},
});
// Export APIs throughout your app
export const { styled, css, globalCss, keyframes, getCssText, Provider, useTheme } = stoop;
Key Changes:
createStitches→createStoop- Add
themesobject for multi-theme support (optional but recommended) themebecomes the default theme- Get
ProvideranduseThemewhenthemesis provided
Step 3: Component Variants
Variants work exactly the same way - no changes needed.
const Button = styled('button', {
padding: '$medium',
borderRadius: '$default',
variants: {
size: {
small: { padding: '$small' },
large: { padding: '$large' },
},
variant: {
primary: { backgroundColor: '$primary' },
secondary: { backgroundColor: '$secondary' },
},
},
});
Step 4: Handle Compound Variants
Stoop does not currently support compound variants (planned for future release). Most projects don't use compound variants, and regular variants are usually sufficient. If you use compound variants, refactor them using one of these approaches:
Before (Stitches):
const Button = styled('button', {
variants: {
size: { small: {}, large: {} },
variant: { primary: {}, secondary: {} },
},
compoundVariants: [
{
size: 'small',
variant: 'primary',
css: { fontWeight: '$bold', textTransform: 'uppercase' },
},
],
});
Option 1: Use conditional css prop (Recommended)
const Button = styled('button', {
variants: {
size: { small: {}, large: {} },
variant: { primary: {}, secondary: {} },
},
});
// In your component
function MyButton({ size, variant, ...props }) {
const isSmallPrimary = size === 'small' && variant === 'primary';
return (
<Button
size={size}
variant={variant}
css={isSmallPrimary ? { fontWeight: '$bold', textTransform: 'uppercase' } : undefined}
{...props}
/>
);
}
Option 2: Create a wrapper component
const ButtonBase = styled('button', {
variants: {
size: { small: {}, large: {} },
variant: { primary: {}, secondary: {} },
},
});
const Button = ({ size, variant, ...props }) => {
const compoundStyles = size === 'small' && variant === 'primary'
? { fontWeight: '$bold', textTransform: 'uppercase' }
: undefined;
return <ButtonBase size={size} variant={variant} css={compoundStyles} {...props} />;
};
Option 3: Use separate variant values
const Button = styled('button', {
variants: {
size: {
small: {},
'small-primary': { fontWeight: '$bold', textTransform: 'uppercase' },
large: {},
},
variant: { primary: {}, secondary: {} },
},
});
Step 5: Update Imports
Before (Stitches):
import { styled, css } from '@stitches/react';
After (Stoop):
import { styled, css } from './stoop.theme'; // or wherever you export from
Step 6: Update SSR Setup
Next.js Pages Router
Before (Stitches):
// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document';
import { getCssText } from '../stitches.config';
export default function Document() {
return (
<Html>
<Head>
<style id="stitches" dangerouslySetInnerHTML={{ __html: getCssText() }} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
After (Stoop):
// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document';
import { getCssText } from '../stoop.theme';
export default function Document() {
return (
<Html>
<Head>
<style id="stoop-styles" dangerouslySetInnerHTML={{ __html: getCssText() }} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
Key Change: getCssText() no longer accepts a theme parameter - it includes all configured themes.
Next.js App Router
Before (Stitches): Stitches has limited support for App Router.
After (Stoop):
// app/components/Styles.tsx
'use client';
import { useServerInsertedHTML } from 'next/navigation';
import { getCssText } from '../stoop.theme';
export function Styles() {
useServerInsertedHTML(() => {
return (
<style
id="stoop-styles"
dangerouslySetInnerHTML={{ __html: getCssText() }}
suppressHydrationWarning
/>
);
});
return null;
}
// app/layout.tsx
import { Styles } from './components/Styles';
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<Styles />
<Providers>{children}</Providers>
</body>
</html>
);
}
Step 7: Add Theme Provider (Recommended)
Stoop provides a built-in Provider component for theme management.
Before (Stitches): No built-in Provider - manual theme management required.
After (Stoop):
// app/providers.tsx
'use client';
import { Provider } from './stoop.theme';
export function Providers({ children }) {
return <Provider>{children}</Provider>;
}
Step 8: Update Theme Switching
Before (Stitches):
// Manual theme management
const darkTheme = createTheme('dark-theme', { ... });
// Manual CSS variable updates
After (Stoop):
// app/components/ThemeToggle.tsx
'use client';
import { useTheme } from './stoop.theme';
export function ThemeToggle() {
const { themeName, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
Current theme: {themeName}
</button>
);
}
What Stays the Same
These features work identically:
- Theme token syntax (
$token,$scale.token) - Base styles (CSS object syntax)
- Variants API (same structure)
- CSS prop
- Polymorphic components (
asprop) - Media queries
- Utility functions
globalCssandkeyframesAPIs
Breaking Changes Summary
- Compound Variants - Not currently supported (planned for future) - use conditional logic or
cssprop (most projects don't need compound variants) - Theme Configuration - Add
themesobject for multi-theme support (optional but recommended) - getCssText() - No longer accepts theme parameter - includes all themes (simpler API)
- Multi-theme - Requires Provider wrapper (but much easier to use than manual theme management)
Troubleshooting
Issue: Compound variants not working
Solution: Refactor to use conditional css prop, wrapper component, or separate variant values. See Step 4 above.
Issue: Theme switching not working
Solution: Make sure you're using the Provider component and useTheme() hook. Provider must wrap your app.
Issue: SSR styles not appearing
Solution: Ensure getCssText() is called in your document/layout and styles are injected before React hydrates. For App Router, use useServerInsertedHTML.
Issue: Type errors with variants
Solution: Variants work the same way as Stitches. Ensure your variants object follows the same structure.
Issue: Theme tokens not resolving
Solution: Make sure your theme configuration includes all scales you're using. Stoop uses CSS variables, so tokens resolve at runtime.
Migration Time Estimate
- Small project (< 50 components): 1-2 hours
- Medium project (50-200 components): 2-4 hours
- Large project (> 200 components): 4-8 hours
Factors affecting time:
- Number of compound variants (major factor)
- Custom utility functions
- Complex theme setup
- SSR configuration complexity
After Migration
- Test all components thoroughly
- Verify theme switching works
- Check SSR rendering
- Update any custom utilities if needed
- Consider using Stoop's built-in multi-theme features
Related Pages
- Installation Guide - Get started with Stoop
- Theme Setup - Configure your theme
- Creating Components - Learn how to create styled components
- API Reference - Complete API documentation