Installation

Next.js

From an empty folder to WAVEINNO components on screen, in the App Router. Every step is needed once per project; after that, import and use.

Requirements

Next.js 16 or newer, React 19, Tailwind CSS 4 and Node.js 20 or newer. Starting from an existing app? Skip step 1.
  1. Create the app

    Answer “Yes” to TypeScript, Tailwind CSS and the App Router. Tailwind CSS 4 is what create-next-app sets up today.

    $ npx create-next-app@latest my-app --ts --tailwind --app --eslint
  2. Install the package

    $ npm install @waveinno/ui

    It brings its own Radix primitives, icons (lucide-react), charts and table engine. react, react-dom, next and tailwindcss are yours, so there is only ever one copy of each.

  3. Add the styles

    Replace the contents of app/globals.css. The package's stylesheet holds the design tokens (colours, radius, density, motion) for light and dark; the @source line lets Tailwind generate the classes the components use.

    app/globals.css
    @import "tailwindcss";
    @import "@waveinno/ui/styles.css";
    
    /* Tailwind only generates classes it can see. Point it at the package,
       relative to this file: "../node_modules" for app/globals.css,
       "../../node_modules" for src/app/globals.css. */
    @source "../node_modules/@waveinno/ui/dist";
    
    /* The fonts loaded in layout.tsx, in the package's font slots.
       Noto Sans Bengali carries Bangla and the Taka sign (৳), which Inter lacks. */
    :root {
      --font-inter: var(--font-body), var(--font-bangla);
      --font-jakarta: var(--font-display), var(--font-bangla);
      --font-jetbrains: var(--font-code);
    }
  4. Add the providers

    One client file, used once in the layout. NextRouterProvider makes every link in the package (the shell's rail, breadcrumbs, the command palette) a Next.js link, with prefetching and no full page loads.

    app/providers.tsx
    "use client";
    
    import { Toaster, TooltipProvider } from "@waveinno/ui";
    import { NextRouterProvider } from "@waveinno/ui/next";
    
    /** Once, around the whole app: Next.js routing for the package, tooltips, toasts. */
    export function Providers({ children }: { children: React.ReactNode }) {
      return (
        <NextRouterProvider>
          <TooltipProvider delayDuration={300}>
            {children}
            <Toaster />
          </TooltipProvider>
        </NextRouterProvider>
      );
    }
  5. Set up the layout: fonts, theme, providers

    next/font self-hosts the four families the system uses (see Typography). themeBootScript() runs before the first paint, so a dark-mode user never sees a white flash.

    app/layout.tsx
    import type { Metadata } from "next";
    import { Inter, JetBrains_Mono, Noto_Sans_Bengali, Plus_Jakarta_Sans } from "next/font/google";
    
    import { themeBootScript } from "@waveinno/ui";
    
    import "./globals.css";
    import { Providers } from "./providers";
    
    const body = Inter({ subsets: ["latin"], variable: "--font-body" });
    const display = Plus_Jakarta_Sans({ subsets: ["latin"], weight: ["500", "600", "700"], variable: "--font-display" });
    const code = JetBrains_Mono({ subsets: ["latin"], variable: "--font-code" });
    const bangla = Noto_Sans_Bengali({ subsets: ["bengali"], variable: "--font-bangla" });
    
    export const metadata: Metadata = { title: "My app" };
    
    export default function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        // The boot script sets data-theme before React runs, so the attribute
        // differs from the server's HTML on purpose.
        <html lang="en" suppressHydrationWarning className={[body.variable, display.variable, code.variable, bangla.variable].join(" ")}>
          <head>
            {/* Applies the saved light/dark theme and density before first paint: no flash. */}
            <script dangerouslySetInnerHTML={{ __html: themeBootScript() }} />
          </head>
          <body className="bg-canvas text-body antialiased">
            <Providers>{children}</Providers>
          </body>
        </html>
      );
    }
  6. Use a component

    Components are client components already (they carry "use client"), so they work straight from a server page.

    app/page.tsx
    import { Alert, Button, StatCard } from "@waveinno/ui";
    
    export default function Home() {
      return (
        <main className="mx-auto max-w-3xl space-y-6 p-8">
          <h1 className="disp text-3xl font-bold">Hello, WAVEINNO</h1>
          <div className="grid gap-4 sm:grid-cols-2">
            <StatCard label="Revenue today" value="48,250" currency delta={12.4} variant="gradient" />
            <StatCard label="Cars inside" value="312" delta={6.2} />
          </div>
          <Alert tone="success" title="It works">The components, the tokens and the fonts are in.</Alert>
          <Button variant="primary">Get started</Button>
        </main>
      );
    }
    $ npx next dev

Optional: the application shell#

Products built on WAVEINNO (ParkingOS, the Admin portal) run inside AppShell: the icon rail, the module panel, the top bar, ⌘K and the record drawer. It needs the providers from step 4 and a config describing your apps and modules.

app/(app)/shell.tsx
"use client";

import { AppShell, type ShellConfig } from "@waveinno/ui";

// Apps, modules and their screens: the rail, the panel and ⌘K are drawn from this.
const config: ShellConfig = {
  apps: [/* { id, name, icon, tint, href, … } */],
  modules: [/* { key, app, title, label, icon, href, nav: [ … ] } */],
  user: { name: "Karim Ahmed", email: "karim@example.com", role: "Owner" },
};

export function Shell({ children }: { children: React.ReactNode }) {
  return <AppShell config={config}>{children}</AppShell>;
}

Troubleshooting#

  • Components look unstyled or half-styled. The @source path is wrong for where your CSS file lives. It is relative to the CSS file, and must reach node_modules/@waveinno/ui/dist.
  • A white flash before dark mode. The boot script is missing from <head>, or suppressHydrationWarning is missing from <html>.
  • “৳” shows as a box, or Bangla falls back to a system font. Noto Sans Bengali is not loaded, or not in the font slots in globals.css.
  • Tooltips never open. TooltipProvider is missing; it lives in the providers file.
  • Shell links reload the whole page. NextRouterProvider is missing; without it the package falls back to plain links.