React Router
Set up Vortex in an existing React Router project in framework mode. Remix v2 apps need to upgrade to React Router first.
Install the packages
Vortex packages are private and available by invitation. Complete the package access prerequisites before installing.
bun add @vortexlabs/vortex @vortexlabs/vortex-themesbun add -d postcss@^8 @csstools/postcss-global-data postcss-custom-media cssnanoGenerate your theme
Create vortex.config.ts at your project root. Replace acme with your theme name; an empty definition inherits Vortex's defaults.
import type { VortexThemeConfig } from "@vortexlabs/vortex-themes";
const config: VortexThemeConfig = {
themes: {
acme: {},
},
};
export default config;Add a script to your existing package.json:
"scripts": {
"build:theme": "vortex-themes theming --output ./app/themes"
}bun run build:themeThis creates app/themes/acme/. Run it again after changing vortex.config.ts or upgrading Vortex packages, before starting or building your app.
Configure PostCSS
Vortex styles use @custom-media breakpoint queries that your build must resolve. Add the package's PostCSS preset:
import { config } from "@vortexlabs/vortex/config/postcss";
export default config;If you already have a PostCSS config, merge the preset's plugins into it. If you customize breakpoints, point PostCSS at your generated definitions; see Custom breakpoints.
Bundle Vortex for server rendering
Add Vortex to ssr.noExternal so Vite processes its CSS Modules for the server build. Without it, the production server fails to start. Keep your existing plugins and options.
import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [reactRouter()],
ssr: {
noExternal: ["@vortexlabs/vortex"],
},
});Restart the dev server after configuration changes.
Add the provider and theme
In your root route, import the generated theme, wrap children with VortexProvider, and set the theme attributes on <html> so the first paint uses the right theme:
import "./themes/acme/globals.css";
import { VortexProvider } from "@vortexlabs/vortex";
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
import type React from "react";
type Props = {
children: React.ReactNode;
};
export const Layout = (props: Props) => {
const { children } = props;
return (
<html lang="en" data-vortex-theme="acme" data-vortex-color-mode="light">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<VortexProvider defaultTheme="acme" defaultColorMode="light">
{children}
</VortexProvider>
<ScrollRestoration />
<Scripts />
</body>
</html>
);
};
const App = () => <Outlet />;
export default App;Use a component
import { Button, Stack, Text } from "@vortexlabs/vortex";
const Home = () => (
<Stack gap={4}>
<Text as="h1" size={{ xs: "heading-xl-mobile", sm: "heading-xl-desktop" }}>Hello Vortex</Text>
<Button variant="primary">Get started</Button>
</Stack>
);
export default Home;bun run devFonts
Vortex doesn't load font files. Follow the Fonts guide to load the default fonts or your own.