Also available as vitreui— the same library under a shorter name.npm i vitreui
Skip to content

SSR & Next.js

Lucent is server-render safe. Presentational components render on the server with no client bundle; interactive components carry their own "use client" boundary so they slot cleanly into React Server Component trees.

The "use client" boundary

The build preserves the "use client" directive on interactive modules (verified by a build-output grep gate). In a Next.js App Router project you can import a server-safe component directly in a Server Component, and an interactive one drops its own boundary:

tsx
// app/page.tsx — a Server Component
import { Card } from '@orionshub/lucent/card'
import { Button } from '@orionshub/lucent/button'
import '@orionshub/lucent/styles.css'

export default function Page() {
  return (
    <Card>
      <Card.Body>Rendered on the server.</Card.Body>
      <Card.Footer><Button>Interactive — ships its own "use client"</Button></Card.Footer>
    </Card>
  )
}

Import server-safe components via subpaths in Server Components

The root barrel (@orionshub/lucent) re-exports the theming provider, which uses React hooks — so it is intended for client trees. In a Server Component, import server-safe components from their per-component subpath (@orionshub/lucent/card, @orionshub/lucent/button, …). Interactive components carry their own "use client", so importing them (from a client file, or as a rendered child) drops a client boundary automatically.

Which components are client vs server-safe is noted on every component page under Guidance → SSR / Next.js.

No theme flash

If you persist a theme and server-render, set the :root attributes before first paint to avoid a flash of the default theme. Inject the no-flash script into <head>:

tsx
import { noFlashScript } from '@orionshub/lucent/no-flash'

// Next.js App Router — app/layout.tsx (a Server Component)
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <script dangerouslySetInnerHTML={{ __html: noFlashScript }} />
      </head>
      <body>{children}</body>
    </html>
  )
}

The script reads the persisted theme from localStorage inside a try/catch and applies the :root attributes synchronously — no template literals, no eval, safe to inline.

CSS import location

Import @orionshub/lucent/styles.css once in the root layout (app/layout.tsx) or _app.tsx. It is a side-effect CSS import and is safe during SSR.

The docs prove it

This site is itself the proof: every live example is a client-only island. The pages statically render (SSR/SSG) without the React runtime, and the examples hydrate on the client — demonstrating that importing Lucent never forces client-side rendering of a page.

A minimal Next.js App Router smoke build (in the repo's apps/next-smoke) additionally compiles a Server Component importing both a server-safe and a client component, gating on next build in CI.

Released under the MIT License.