Skip to content

Next.js

oks-ui works with the Next.js App Router and with static export. Three things to know: where the client boundary goes, how the CSS is imported, and how the theme script runs.

LiveOverview
  • app/layout.tsxServer
  • app/globals.cssCSS
  • app/page.tsxServer
  • components/Toolbar.tsxuse client

The client boundary sits around the files that use oks-ui components.

1. Client boundaries

Since oks-ui 1.3.1, the per-component entries (oks-ui/button, oks-ui/modal, and so on) and oks-ui/motion are marked as client components, with two exceptions below. Import them straight into a Server Component; Next still prerenders their initial HTML. Function props such as onPress cannot be passed down from a Server Component, so put anything interactive in a file that starts with "use client".

// app/page.tsx  (a Server Component, no "use client")
import { Button } from "oks-ui/button";
import "oks-ui/button.css";

const Page = () => {
  return <Button color="primary">Get started</Button>;
};

export default Page;

Two entries are deliberately not marked because they also export plain functions a server can call: oks-ui/text-editor (blocksToHtml, blocksToMarkdown) and oks-ui/pagination (paginationRange). The main oks-ui entry is unmarked for the same reason (it exports helpers such as oksVar). Importing a component from any of these into a Server Component, or importing any component on oks-ui 1.2.x, fails the build with TypeError: (0 , c.useState) is not a function. Use the marked per-component entries, or move the import into a "use client" file.

2. CSS imports

Import oks-ui/styles.css once in your root layout, or — for the smallest bundle — import each component's .css alongside it. Turbopack does not follow the stylesheet import that lives inside oks-ui/button, so add the .css line explicitly.

3. The no-flash theme script

// app/layout.tsx
import Script from "next/script";

const RootLayout = ({ children }) => {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Script id="theme" strategy="beforeInteractive">{`
          try {
            var s = localStorage.getItem("theme");
            var d = s === "dark" ||
              (!s && matchMedia("(prefers-color-scheme: dark)").matches);
            document.documentElement.setAttribute("data-theme", d ? "dark" : "light");
          } catch (e) {}
        `}</Script>
        {children}
      </body>
    </html>
  );
};

export default RootLayout;

This whole site is a Next.js static export built on oks-ui, so every page you are reading is the library running in production.