npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@next-library/theme

v1.0.4

Published

Complete UI theme for Next.js documentation framework

Readme

@next-library/theme

Complete UI theme package for Next.js documentation framework. This package provides ready-made React components built on top of @next-library/core.

Looking for core utilities only? See @next-library/core.

Content tree: Layout and nav expect the same PageData from extractPageData(contentTree, locale, slug). Import contentTree from your generated lib/tree.ts and pass contentTree into NavigationBar (and derive getSupportedLocales(contentTree) for LanguageSwitcher). The canonical wiring is example/app/ and docs/getting-started.md.

Features

  • 🎨 Complete UI Components - Layout, navigation, markdown rendering, and more
  • 🌍 Multi-language Support - Built-in translations for 20+ languages
  • 📱 Responsive Design - Mobile-first with drawer navigation and responsive breadcrumbs
  • 🎯 Type-Safe - Full TypeScript support
  • Server/Client Separation - Optimized for Next.js App Router
  • 🎭 Theme Support - Dark mode with next-themes
  • 📝 Rich Markdown - Syntax highlighting, math, diagrams, callouts

Installation

# Using npm
npm install @next-library/theme @next-library/core

# Using pnpm
pnpm add @next-library/theme @next-library/core

# Using yarn
yarn add @next-library/theme @next-library/core

Required peer dependencies:

  • next-themes - For theme switching (dark/light mode)
  • @tailwindcss/typography - For markdown prose styling
pnpm add next-themes @tailwindcss/typography

Quick Start

1. Set Up Tailwind CSS v4

The theme package uses Tailwind CSS v4 with @source directives (Nextra-style approach). Create or update your globals.css:

/* app/globals.css */
@import 'tailwindcss';
@plugin "@tailwindcss/typography";

/* Import theme package styles to scan for Tailwind classes */
@import '@next-library/theme/style';

@custom-variant dark (&:is(.dark *));

:root {
  /* Your CSS variables */
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  /* ... more variables */
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  /* ... more variables */
}

Important: The @import '@next-library/theme/style' line tells Tailwind where to scan for classes used in the theme components.

2. Set Up Theme Provider

Create a theme provider wrapper:

// app/providers.tsx
'use client';

import { ThemeProvider as NextThemesProvider } from 'next-themes';
import { ReactNode } from 'react';

export function ThemeProvider({ children }: { children: ReactNode }) {
  return (
    <NextThemesProvider attribute="class" defaultTheme="system" enableSystem>
      {children}
    </NextThemesProvider>
  );
}

Wrap your app in app/layout.tsx:

// app/layout.tsx
import { ThemeProvider } from './providers';

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

3. Use Components

Server Components

Import server components from @next-library/theme/server:

// app/[locale]/layout.tsx
import { DocumentationLayout } from '@next-library/theme/server';
import { isValidLocale, type Locale } from '@next-library/core';

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale: raw } = await params;
  const locale = (isValidLocale(raw) ? raw : 'en') as Locale;

  return (
    <DocumentationLayout language={locale}>
      {children}
    </DocumentationLayout>
  );
}

Client Components

Import client components from @next-library/theme/client:

Server parent (derive locales from the generated tree):

import { getSupportedLocales } from '@next-library/core';
import contentTree from '@/lib/tree';
import { LocaleTools } from './locale-tools';

const availableLocales = getSupportedLocales(contentTree);
// …
<LocaleTools availableLocales={availableLocales} />;

Client component:

// app/locale-tools.tsx
'use client';

import { LanguageSwitcher, ThemeSwitcher } from '@next-library/theme/client';

export function LocaleTools({ availableLocales }: { availableLocales: string[] }) {
  return (
    <div>
      <LanguageSwitcher availableLocales={availableLocales} />
      <ThemeSwitcher />
    </div>
  );
}

NavigationBar computes locales from contentTree when you pass contentTree (see complete example below).

Component Exports

Server Components (@next-library/theme/server)

  • DocumentationLayout - Main layout wrapper
  • NavigationBar - Top navigation bar
  • LeftSidebar - Left sidebar navigation
  • RightSidebar - Right sidebar (TOC, contributors)
  • DocumentationFooter - Footer component
  • StructuredData - JSON-LD structured data renderer

Client Components (@next-library/theme/client)

Navigation:

  • Banner - Top banner component
  • Logo - Logo component
  • TopCategories - Top category navigation
  • SearchBar - Search input with keyboard shortcuts
  • ThemeSwitcher - Dark/light theme toggle
  • LanguageSwitcher - Language selection dropdown
  • MobileMenu - Mobile navigation drawer
  • GithubStar - GitHub star button
  • GithubLink - GitHub repository link
  • Breadcrumbs - Breadcrumb navigation
  • BreadcrumbToggle - Responsive breadcrumb overflow
  • FolderCards - Grid of folder cards
  • SidebarNavigation - Sidebar navigation tree
  • TableOfContents - Table of contents
  • GithubContributors - Contributors list
  • LevelElevator - Current level indicator
  • AnchorLinkHandler - Anchor link copying

Markdown:

  • MarkdownRenderer - Markdown content renderer
  • CopyPageButton - Copy page content button with ChatGPT/Claude integration
  • PageHeader - Page title with copy button
  • FallbackLocaleWarning - Warning for fallback locale content

UI Primitives:

  • Button, Card, Avatar, Collapsible, Drawer, DropdownMenu, Select, Separator, Sheet, Tooltip, Input, Skeleton
  • Sidebar components (SidebarProvider, SidebarContent, SidebarMenu, etc.)
  • Breadcrumb components (Breadcrumb, BreadcrumbItem, etc.)

Tracking:

  • CookieBanner - Cookie consent banner

Hooks:

  • useMediaQuery - Media query hook
  • useIsMobile - Mobile detection hook

Complete Example

Layout Structure

// app/[locale]/layout.tsx
import { DocumentationLayout } from '@next-library/theme/server';
import { isValidLocale, type Locale } from '@next-library/core';

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale: rawLocale } = await params;
  const locale = (isValidLocale(rawLocale) ? rawLocale : 'en') as Locale;

  return (
    <DocumentationLayout language={locale}>
      {children}
    </DocumentationLayout>
  );
}

Documentation Page Layout

// app/[locale]/docs/[[...slug]]/layout.tsx
import { NavigationBar, LeftSidebar, RightSidebar } from '@next-library/theme/server';
import { Breadcrumbs, AnchorLinkHandler } from '@next-library/theme/client';
import { extractPageData, isValidLocale, createConfig, type Locale } from '@next-library/core';
import { libraryConfig } from '@/library.config';
import contentTree from '@/lib/tree';

export default async function DocsLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string; slug?: string[] }>;
}) {
  const { locale: rawLocale, slug } = await params;
  const locale = (isValidLocale(rawLocale) ? rawLocale : 'en') as Locale;
  const safeSlug = Array.isArray(slug) ? slug : [];
  const fullConfig = createConfig(libraryConfig);
  const pageData = extractPageData(contentTree, locale, safeSlug);
  const repoUrl =
    fullConfig.github?.user && fullConfig.github?.repo
      ? `https://github.com/${fullConfig.github.user}/${fullConfig.github.repo}`
      : undefined;

  return (
    <div>
      <NavigationBar
        language={locale}
        className="block lg:hidden"
        pageData={pageData}
        websiteTitle={fullConfig.website?.title || 'Documentation'}
        contentTree={contentTree}
        repoUrl={repoUrl}
      />
      <div className="flex flex-row gap-12 w-full lg:w-[95vw] mx-auto pt-10">
        <LeftSidebar
          data={pageData}
          className="sticky top-28 hidden lg:flex lg:flex-[2] max-w-xs"
        />
        <main className="flex flex-col lg:gap-8 gap-4 flex-1 w-full lg:flex-[6] px-4 lg:px-0">
          <Breadcrumbs data={pageData} locale={locale} />
          {children}
        </main>
        <RightSidebar
          data={pageData}
          className="sticky top-28 hidden lg:flex lg:flex-[1.5] max-w-xs"
        />
        <AnchorLinkHandler locale={locale} />
      </div>
    </div>
  );
}

Documentation Page

// app/[locale]/docs/[[...slug]]/page.tsx (leaf page — folder views need FolderCards; see example app)
import {
  extractPageData,
  isValidLocale,
  fetchRawFileContent,
  createConfig,
  type Locale,
} from '@next-library/core';
import { PageHeader, FallbackLocaleWarning } from '@next-library/theme/server';
import { MarkdownRenderer } from '@next-library/theme/client';
import { libraryConfig } from '@/library.config';
import contentTree from '@/lib/tree';
import { notFound } from 'next/navigation';

export default async function DocPage({
  params,
}: {
  params: Promise<{ locale: string; slug?: string[] }>;
}) {
  const { locale: rawLocale, slug } = await params;
  const locale = (isValidLocale(rawLocale) ? rawLocale : 'en') as Locale;
  const safeSlug = Array.isArray(slug) ? slug : [];
  const fullConfig = createConfig(libraryConfig);
  const pageData = extractPageData(contentTree, locale, safeSlug);
  const { node } = pageData;

  if (!node?.githubPath || !fullConfig.github?.user || !fullConfig.github?.repo) {
    notFound();
  }

  const githubConfig = {
    user: fullConfig.github.user,
    repo: fullConfig.github.repo,
    branch: fullConfig.github.branch || 'main',
    token: fullConfig.github.token,
    app: fullConfig.github.app,
  };
  const rawMarkdown = await fetchRawFileContent(node.githubPath, githubConfig);
  const baseUrl = fullConfig.website?.siteUrl || 'http://localhost:3000';
  const pageUrl = `${baseUrl.replace(/\/$/, '')}/${locale}/docs/${safeSlug.join('/')}`;
  const websiteTitle = fullConfig.website?.title || fullConfig.website?.organizationName || 'Documentation';

  return (
    <div>
      <PageHeader
        title={node.title}
        markdown={rawMarkdown}
        pageUrl={pageUrl}
        websiteTitle={websiteTitle}
        locale={locale}
      />
      {node.fallback && <FallbackLocaleWarning locale={locale} />}
      <MarkdownRenderer markdown={rawMarkdown} />
    </div>
  );
}

For JSON-LD, generateMetadata, folder index views (FolderCards), and error handling, copy from example/app/[locale]/docs/[[...slug]]/page.tsx in the monorepo.

Internationalization

The theme package includes translations for 20+ languages. Components automatically use translations based on the locale prop:

import { CopyPageButton } from '@next-library/theme/client';

// Uses default translations for locale
<CopyPageButton 
  sourceCode={markdown}
  locale="fr" // French translations will be used
/>

// Override specific translations
<CopyPageButton 
  sourceCode={markdown}
  locale="fr"
  translations={{
    copyPage: 'Copier la page',
    copied: 'Copié',
  }}
/>

Supported Locales

  • English (en)
  • French (fr)
  • German (de)
  • Spanish (es)
  • Arabic (ar) - RTL support
  • Chinese (zh)
  • Japanese (ja)
  • Korean (ko)
  • Portuguese (pt)
  • Italian (it)
  • Russian (ru)
  • Dutch (nl)
  • Swedish (sv)
  • Norwegian (no)
  • Danish (da)
  • Finnish (fi)
  • Polish (pl)
  • Turkish (tr)
  • Hebrew (he) - RTL support
  • Hindi (hi)

Custom Translations

All components accept an optional translations prop to override default translations:

interface ComponentTranslations {
  // Component-specific translation keys
  copyPage?: string;
  copied?: string;
  // ... more keys
}

Styling

Tailwind CSS v4

The theme uses Tailwind CSS v4 with @source directives. Make sure to import the theme style file in your globals.css:

@import '@next-library/theme/style';

This tells Tailwind where to scan for classes used in theme components.

CSS Variables

The theme uses CSS variables for theming. Define your variables in globals.css:

:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  /* ... more variables */
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  /* ... more variables */
}

Customization

You can customize component styles by:

  1. Overriding CSS variables - Change theme colors via CSS variables
  2. Using className prop - Most components accept className for additional styling
  3. Tailwind classes - All components use Tailwind, so you can override with utility classes

Component Props

DocumentationLayout

interface DocumentationLayoutProps {
  children: React.ReactNode;
  language?: Locale;
  bannerMessage?: React.ReactNode | null;
  websiteTitle?: string;
}

NavigationBar

interface NavigationBarProps {
  language?: Locale;
  className?: string;
  pageData?: PageData;
  websiteTitle?: string;
  contentTree?: ContentTree;
  repoUrl?: string;
}

PageHeader

interface PageHeaderProps {
  title: string;
  markdown: string;
  pageUrl?: string;
  websiteTitle?: string;
  className?: string;
  locale?: Locale;
  translations?: CopyPageButtonTranslations;
  showCopyButton?: boolean;
}

CopyPageButton

interface CopyPageButtonProps {
  sourceCode: string;
  pageUrl?: string;
  websiteTitle?: string;
  className?: string;
  locale?: Locale;
  translations?: CopyPageButtonTranslations;
}

The CopyPageButton includes integration with ChatGPT and Claude:

  • Copy page - Copies markdown content to clipboard
  • Open in ChatGPT - Opens ChatGPT with prefilled message including website title and URL
  • Open in Claude - Opens Claude with prefilled message including website title and URL

Server/Client Separation

The theme package properly separates server and client components:

  • Server components are imported from @next-library/theme/server
  • Client components are imported from @next-library/theme/client
  • Server components can import client components (they're externalized in the build)

This ensures optimal performance with Next.js App Router.

TypeScript Support

The package is fully typed. Import types as needed:

import type {
  DocumentationLayoutProps,
  NavigationBarProps,
  PageHeaderProps,
  CopyPageButtonProps,
} from '@next-library/theme/server';

Examples

See the example directory for a complete working example.

API Reference

Server Components

  • DocumentationLayout - Main layout wrapper
  • NavigationBar - Top navigation
  • LeftSidebar - Left sidebar navigation
  • RightSidebar - Right sidebar (TOC, contributors)
  • DocumentationFooter - Footer
  • StructuredData - JSON-LD renderer

Client Components

See the Component Exports section above for the complete list.

Contributing

Contributions are welcome! Please see our contributing guide for details.

License

MIT

Support