Next.js
Set up Vortex in a Next.js App Router project.
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 cssnanoFor TypeScript projects, align the React types with React 19:
bun add -d @types/react@^19 @types/react-dom@^19Generate 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. The CLI is included in @vortexlabs/vortex-themes.
"scripts": {
"build:theme": "vortex-themes theming --output ./src/themes"
}bun run build:themeThis creates src/themes/acme/. Run the script again after changing vortex.config.ts or upgrading Vortex or Vortex Themes, 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; responsive styles don't work without it.
import { config } from "@vortexlabs/vortex/config/postcss";
export default config;If you already have a PostCSS config, merge the preset's plugins into it. Restart the dev server after configuration changes.
If you customize breakpoints, point PostCSS at your generated definitions; see Custom breakpoints.
Configure package transpilation
Add Vortex to transpilePackages so Next.js processes the package and its CSS Modules. Keep any other options in your existing config.
Use Vortex 0.15.1 or later with Turbopack; it fixes Text Field CSS Modules compilation in 0.15.0.
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
transpilePackages: ["@vortexlabs/vortex"],
};
export default nextConfig;Add the provider and theme
Create a client boundary for the provider:
"use client";
import { VortexProvider } from "@vortexlabs/vortex";
import type React from "react";
type Props = {
children: React.ReactNode;
};
const Providers = (props: Props) => {
const { children } = props;
return (
<VortexProvider defaultTheme="acme" defaultColorMode="light">
{children}
</VortexProvider>
);
};
export default Providers;Import the generated theme once in your root layout and wrap your app with Providers. For src/app/, use ../themes/acme/globals.css.
Set data-vortex-theme and data-vortex-color-mode on <html> to match the provider, so the first paint uses the right theme. suppressHydrationWarning prevents warnings when these attributes change before hydration, such as from a saved preference.
import "../src/themes/acme/globals.css";
import type React from "react";
import Providers from "./providers";
type Props = {
children: React.ReactNode;
};
const RootLayout = (props: Props) => {
const { children } = props;
return (
<html
lang="en"
data-vortex-theme="acme"
data-vortex-color-mode="light"
suppressHydrationWarning
>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
};
export default RootLayout;Render components
Vortex components need a Client Component ("use client"), since they use React context and refs. Wrapping a page in Providers doesn't make it one.
"use client";
import { Button, Stack, Text } from "@vortexlabs/vortex";
const Page = () => (
<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 Page;See the Next.js client boundary guide for composing server and client components.
Fonts
Vortex doesn't load font files. Follow the Fonts guide to load the default fonts or your own.