Skip to content

Latest commit

 

History

History
177 lines (133 loc) · 5.3 KB

File metadata and controls

177 lines (133 loc) · 5.3 KB

Next.js App Router with SSR

This example demonstrates how to integrate @clickhouse/click-ui with Next.js 16 App Router and Server-Side Rendering (SSR).

Configuration

Before installing Click UI, configure transpilePackages (available in Next.js 13+) in your Next.js config next.config.ts:

module.exports = {
  transpilePackages: ['@clickhouse/click-ui'],
};

Important

The transpilePackages option is required because Click UI distributes CSS colocated with components. Next.js restricts global CSS imports from node_modules by default. Transpiling the package allows Next.js to process the CSS through its build pipeline, preventing the "Global CSS cannot be imported from within node_modules" error.

Quick Start

Install the package:

npm i @clickhouse/click-ui@latest

Theme Provider Setup

Create a client-side theme provider that wraps your application with ClickUIProvider, e.g. app/ThemeProvider.tsx:

"use client";

import { useState, type ReactNode } from "react";
import { ClickUIProvider, ThemeName, useInitialTheme } from '@clickhouse/click-ui';

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
  const { theme, mounted } = useInitialTheme({
    defaultTheme: 'light',
  });
  
  const [currentTheme, setCurrentTheme] = useState<ThemeName | null>(theme);

  if (!mounted || !currentTheme) {
    return null;
  }

  return (
    <ClickUIProvider theme={currentTheme} persistTheme>
      {children}
    </ClickUIProvider>
  );
};

App Layout Configuration

Configure the root layout with InitCUIThemeScript in the <head> to prevent theme flash on initial load.

Include suppressHydrationWarning on <html> and <body> elements to suppress warnings caused by theme switching:

import type { Metadata } from "next";
import { ThemeProvider } from './ThemeProvider'
import { InitCUIThemeScript } from '@clickhouse/click-ui';

export const metadata: Metadata = {
  title: "Next.js + Click UI",
  description: "SSR example with Click UI",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <InitCUIThemeScript defaultTheme="light" />
      </head>
      <body>
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

Important

The suppressHydrationWarning prop is required in root html element. This suppresses React hydration mismatch warnings that occur when the server-rendered HTML differs from the client-side hydrated HTML due to theme state. This is a standard practice in component libraries like Material UI when dealing with theme variables.

Switching Theme Colors

Add a theme toggle to your application:

"use client";

import { useState, type ReactNode } from "react";
import { ClickUIProvider, Container, Switch, ThemeName, useInitialTheme } from '@clickhouse/click-ui';

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
  const { theme, mounted } = useInitialTheme({
    defaultTheme: 'light',
  });
  
  const [currentTheme, setCurrentTheme] = useState<ThemeName | null>(theme);

  if (!mounted || !currentTheme) {
    return null;
  }

  return (
    <ClickUIProvider theme={currentTheme} persistTheme>
      <Container orientation='horizontal' gap='sm' alignItems='center'>
        <Switch
          checked={currentTheme === 'dark'}
          onCheckedChange={(checked) => setCurrentTheme(checked ? 'dark' : 'light')}
          label='Dark mode'
        />
      </Container>
      {children}
    </ClickUIProvider>
  );
};

Note

Themes are plain CSS custom properties switched by the data-cui-theme attribute on the root <html> element. There is no runtime style computation, so the only possible flash is the wrong theme on first paint, which InitCUIThemeScript prevents.

Custom Styling with CSS

The data-cui-theme attribute on the root <html> element allows you to extend theming to your own components with vanilla CSS or CSS modules:

[data-cui-theme="light"] {
  --custom-bg: #fff;
  --custom-border: #e5e5e5;
}

[data-cui-theme="dark"] {
  --custom-bg: #121212;
  --custom-border: #333;
}

.my-card {
  background: var(--custom-bg);
  border: 1px solid var(--custom-border);
}

This works immediately on page load without flash because InitCUIThemeScript sets the attribute before React hydration.

Using Components

Use Click UI components in both server and client components:

import { Button, Container, Title } from "@clickhouse/click-ui";

export default function Home() {
  return (
    <Container>
      <Title type="h1">Hello ClickHouse</Title>
      <Button type="primary" label="Get Started" />
    </Container>
  );
}

Note

The useInitialTheme hook handles the initial theme state from localStorage and prevents hydration mismatches by returning mounted: false until the client-side effect runs. This ensures the first render matches the server output.

Tip

Enable persistTheme on ClickUIProvider to automatically save theme changes to localStorage. The InitCUIThemeScript reads this value and applies it immediately before React hydration to prevent theme flashing.