Getting started: TanStack Start
SSR on Vite: the styles are linked from the root route's head() and the theme is set on <html> in shellComponent, so the first paint is already themed
1. Create the app
The --blank flag gives you a minimal template. The full template ships its own theme script that writes data-theme="light|dark" on <html> and conflicts with the ValyroUI theme, so you'd have to remove it. Tested with TanStack Start 1.169.
npx @tanstack/cli@latest create my-app --framework React --blank --package-manager npm --no-git --no-intent --no-toolchain --non-interactive
cd my-app
2. Install the package
Works with react and react-dom 17, 18 and 19 (React 17: ids from useId appear right after mount). The package ships ES modules (plus a CommonJS copy for require()), has no runtime dependencies and has one file per module, so your bundle includes only the components you import; to load only their CSS as well, see “Only the CSS you need” below. Fonts are separate files: the vercel theme (the ThemeProvider default) uses Geist, so import valyro-ui/fonts/geist.css and valyro-ui/fonts/geist-mono.css next to the styles, or text falls back to the system font; glass uses system fonts and needs none. Until the package is published, build and pack it in the repository (npm run build:core && npm pack ./dist/core) and install the tarball from the repository root: npm install /path/to/ValyroUI/valyro-ui-0.1.0.tgz.
npm install valyro-ui
3. Styles and theme in the root route
Importing with ?url turns the CSS into a <link> in the <head> of the server-rendered HTML — that's how the template loads its own CSS too — and makes the order explicit: ValyroUI first, then your styles. A plain import 'valyro-ui/styles.css' also adds a link to <head>, but after the ones from links, so ValyroUI styles override yours. Put the theme attributes on <html> and wrap children in ThemeProvider with the same values. With SSR, pass locale to ThemeProvider. Otherwise numbers and dates are formatted in the server locale on the server and in the user locale in the browser, and hydration fails on the mismatched text (“1,200” vs “1 200”).
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
import { ThemeProvider } from 'valyro-ui'
import valyroCss from 'valyro-ui/styles.css?url'
import appCss from '../styles.css?url'
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ title: 'ValyroUI on TanStack Start' },
],
links: [
{ rel: 'stylesheet', href: valyroCss },
{ rel: 'stylesheet', href: appCss },
],
}),
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: React.ReactNode }) {
return (
<html lang="en" data-theme="glass" data-mode="light">
<head>
<HeadContent />
</head>
<body>
<ThemeProvider theme="glass" mode="light" locale="en-US">
{children}
</ThemeProvider>
<Scripts />
</body>
</html>
)
}
4. Remove the template font and layout
The template's font-family on body overrides the theme font, and its main rule changes the page layout. Keep only the reset.
* {
box-sizing: border-box;
}
body {
margin: 0;
}
5. Route
Showcase is the component from the Next.js guide, unchanged (TanStack Start silently ignores the 'use client' directive).
import { createFileRoute } from '@tanstack/react-router'
import { Showcase } from '../Showcase'
export const Route = createFileRoute('/')({ component: Home })
function Home() {
return <Showcase />
}
6. Build and run
npm run preview serves SSR from the production build. To deploy on Node, you need a hosting adapter from the TanStack Start docs.
npx tsc --noEmit
npm run build
npm run preview