Next.js Server Components

Render static Boreal UI directly in Next.js App Router server files. Dedicated server entries avoid client directives, React hooks, browser APIs, and callback props while preserving Boreal styling and accessible markup.

Render on the server

Import static UI from @boreal-ui/next/server without adding a client boundary to the page.

Keep interaction explicit

Use standard @boreal-ui/next entries when a component needs hooks, browser APIs, callbacks, or client state.

Resolve themes before paint

Server-safe theme helpers apply the saved scheme to <html> before the client provider hydrates.

Import Server Entries

Use the server barrel for convenient grouped imports or a standalone path for a single component.

server-barrel.tsxtsx
import {
  BreadCrumbPageHeader,
  Card,
  Container,
  MetricBox,
  Timeline,
} from "@boreal-ui/next/server";
server-subpaths.tsxtsx
import MetricBox from "@boreal-ui/next/server/MetricBox";
import { Grid, Stack } from "@boreal-ui/next/server/Layout";

import "@boreal-ui/next/globals.css";

Available Server Entries

These entries accept serializable render-time values and produce static markup.

Published Next.js server entries
Content and statusAlert, Avatar, Badge, Card, Divider, EmptyState, MetricBox, Skeleton, Typography, and ValidationSummary
Charts and data displayBarChart, Legend, LineChart, ProgressBar, and Sparkline
Navigation and page structureBreadCrumbPageHeader, Breadcrumbs, Footer, PageHeader, Timeline, and Toolbar
Static actions and form controlsButton, CheckBox, RadioButton, RadioGroup, Select, TextArea, and TextInput
LayoutContainer, Grid, Inline, Section, and Stack from the Layout entry
Theme helpersgetThemeAttributes, getThemeStyle, readSavedSchemeCookie, resolveThemeScheme, and THEME_COOKIE_NAME from ThemeProvider

Static and Stripped Behavior

Normally interactive components deliberately expose a smaller server-safe API.

  • Button renders static button or link markup without event callbacks.
  • TextInput and TextArea render read-only values or native initial state.
  • Select, CheckBox, RadioButton, and RadioGroup render native initial form state without change callbacks.
  • EmptyState uses actionHref for a static action link and omits onActionClick.
  • Footer renders links and static social actions, and omits the theme selector.
  • Toolbar renders a static avatar and omits the avatar click handler.
  • ValidationSummary renders linked or plain items without focus-on-mount and item-click behavior.

SSR Theme Setup

Read the Boreal theme cookie in the root layout, apply its attributes to the html element, then wrap the body with the normal client ThemeProvider for interactive theme changes.

app/layout.tsxtsx
import { cookies } from "next/headers";
import { ThemeProvider } from "@boreal-ui/next/ThemeProvider";
import {
  getThemeAttributes,
  resolveThemeScheme,
  THEME_COOKIE_NAME,
} from "@boreal-ui/next/server/ThemeProvider";
import "@boreal-ui/next/globals.css";

export default async function RootLayout({ children }) {
  const cookieStore = await cookies();
  const savedThemeName = cookieStore.get(THEME_COOKIE_NAME)?.value;
  const scheme = resolveThemeScheme(savedThemeName);

  return (
    <html lang="en" {...getThemeAttributes(scheme)}>
      <body>
        <ThemeProvider initialSchemeName={scheme.name}>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

The Next ThemeProvider synchronizes changes to local storage and the boreal-theme cookie by default. For custom schemes, pass the same customSchemes and useOnlyCustomSchemes options to both resolveThemeScheme and the client provider.

Server-Rendered Dashboard

This page remains a Server Component because every Boreal import comes from the server barrel.

app/reports/page.tsxtsx
import {
  BreadCrumbPageHeader,
  Button,
  Card,
  Grid,
  MetricBox,
  Stack,
  ValidationSummary,
} from "@boreal-ui/next/server";

export default function ReportsPage() {
  return (
    <Stack gap="lg">
      <BreadCrumbPageHeader
        breadcrumbs={[{ label: "Dashboard", href: "/" }, { label: "Reports" }]}
        title="Reports"
        actions={<Button href="/reports/archive">View archive</Button>}
      />

      <Grid minColumnWidth="14rem">
        <MetricBox title="Requests" value="12.4" units="k" />
        <MetricBox title="Availability" value="99.99" units="%" />
      </Grid>

      <Card title="Validation status">
        <ValidationSummary
          items={[{ message: "Name is required", fieldId: "name" }]}
        />
      </Card>
    </Stack>
  );
}

Use server entries when

  • Values and markup are known during server render.
  • The component only needs static links, content, or initial form state.
  • You want to avoid adding a client boundary to a route.

Use standard Next entries when

  • The component needs event handlers or client-managed state.
  • The component uses browser APIs, hooks, or context.
  • The UI must react immediately to user interaction.