Docs resource

採用ガイド

下流アプリで GunjoUI を導入するときのインストール、Next.js 設定、Tailwind 設定、テーマ適用の手順です。

GunjoUI を他の Next.js / React プロジェクトに導入する手順。⁠5 分で Button が画面に出るところ⁠ までを目標にしています。

前提

採用先プロジェクトは以下を満たしている:

  • Node.js 20 以上
  • ⁠React 19 以上⁠(peer は ^19.0.0 のみ。React 18 は未サポート)
  • Tailwind CSS v3 または v4(peer 宣言通り)
  • TypeScript(推奨。型定義 .d.ts を同梱)
  • Next.js 15+(推奨 16)または Vite + React

詳細は dependencies.md 参照。配布形態の方針は adoption-strategy.md 参照。

5 分インストール

1. パッケージ追加

0.0.1-alpha.0 から ⁠@gunjo/ui⁠ として npm に publish 済(現在は 0.2.0-beta.x)。beta 段階(1.0 前)のため API は変わり得るが、ドライラン採用は可:

# npm から(推奨、0.0.1-alpha.0 以降)
npm install @gunjo/ui

# 開発中(手元の clone を直接使う場合)
npm install file:../gunjo            # 相対パス推奨
# あるいは絶対パス
npm install /absolute/path/to/gunjo

⁠beta 段階の注意⁠:1.0.0 stable 前は API が変わる可能性あり。本格採用は 0.x シリーズでのドライラン後に判断推奨。バージョン履歴は CHANGELOG.md。

重い部品は subpath から import し、依存を自分で入れる(0.2.0 から)

重いライブラリを使う9部品は、root(@gunjo/ui)からは export していない。部品ごとの入口から import し、その依存(optional peer)を採用先で入れる。使わない部品の依存は入れなくてよい(root から import しても解決しに行かない)。

import する入口部品採用先で入れる依存
@gunjo/ui/tableDataTable・ActionDataTable(型 ColumnDef も)@tanstack/react-table
@gunjo/ui/calendarCalendar・DatePicker・DateRangePickerreact-day-picker
@gunjo/ui/drawerDrawervaul
@gunjo/ui/carouselCarouselembla-carousel-react
@gunjo/ui/markdownMarkdownRendererreact-markdown
@gunjo/ui/motionFloatingPanelframer-motion
import { Button } from "@gunjo/ui";
import { DataTable, type ColumnDef } from "@gunjo/ui/table";
npm install @tanstack/react-table

部品と入口の対応の SSOT は scripts/design-sync/subpath-entries.mjs(npm run design:verify が package.json の exports・peer の宣言・root から重い依存に届かないことを見張る)。0.1.x から上げるときの書き換えは CHANGELOG.md の [Unreleased](出たあとは [0.2.0-beta.1])の移行手順。

2. ビルド設定(不要)

@gunjo/ui は ⁠コンパイル済みの ESM + 型定義を dist/ から配布⁠ している(exports "." → ./dist/index.js、各コンポーネントの "use client" 境界も保持)。そのため ⁠transpilePackages は不要⁠で、npm install してそのまま import できる(Next.js / Vite いずれも追加設定なし)。

旧 alpha(main: "src/index.ts" で生 TS を配布していた頃)は transpilePackages: ["@gunjo/ui"] が必須だった。dist 配布化以降は削除してよい。

Next.js App Router の Server Component から import { X } from "@gunjo/ui" しても、追加の設定なしで next build が通る(0.2.0 から CI で毎回確かめている)。経緯は § Server Component からのバレル import。

3. Tailwind プリセット取り込み

採用先の Tailwind 系統で手順が分岐する。

3a. Tailwind v3 を使っている場合

tailwind.config.ts:

import type { Config } from "tailwindcss";
import gunjoPreset from "@gunjo/ui/tailwind-preset";

const config: Config = {
  presets: [gunjoPreset],
  content: [
    "./app/**/*.{ts,tsx}",
    "./components/**/*.{ts,tsx}",
    "./node_modules/@gunjo/ui/dist/**/*.js", // GunjoUI のクラスもスキャン(コンパイル済み dist)
  ],
};

export default config;

3b. Tailwind v4 を使っている場合

v4 は tailwind.config.ts ベースではなく CSS の @theme ベース。@gunjo/ui/tailwind-preset をそのまま CSS から @config で読み込む方式が最も簡単:

/* app/globals.css */
@import "tailwindcss";
@config "../node_modules/@gunjo/ui/tailwind-preset.js";
@source "../node_modules/@gunjo/ui/dist/**/*.js";
@import "@gunjo/ui/styles";  /* 次節 4 でも触れる token 定義 */

@source で GunjoUI 内部のクラスをスキャン対象に追加する。@config を使わずに直接 @theme ブロックを書きたい場合は、@gunjo/ui/tailwind-theme-extend から token map を取り出して手で写経する形になる(メンテ負担が大きいので非推奨)。

4. グローバル CSS 取り込み

採用先の app/globals.css(Next.js App Router の場合):

@import "tailwindcss";          /* v4。v3 なら従来の @tailwind directives */
@import "@gunjo/ui/styles";        /* GunjoUI のトークン定義 */

v4 採用で前節 3b の @config を使った場合は、@import "@gunjo/ui/styles"; がその CSS 内に既にあるはずなのでここは重複させない。

create-next-app が生成する :root { --background; --foreground; } や @theme inline の既定トークンブロックが残っている場合は、GunjoUI の token と競合しないように削除するか @gunjo/ui/styles の定義へ置き換える。

⁠⚠️ Turbopack dev の注意:⁠ Next.js 16 + Turbopack の npm run dev では、CSS 内の ⁠bare specifier @import "@gunjo/ui/styles"; が解決できず全ルートが 500⁠ になることがある(CssSyntaxError: Can't resolve '@gunjo/ui/styles'。npm run build は成功する dev 限定の挙動)。その場合は ⁠下の app/layout.tsx で JS として import "@gunjo/ui/styles"; する形(推奨)⁠、または CSS 側を相対パス @import "../node_modules/@gunjo/ui/dist/globals.css"; にして回避する。

または app/layout.tsx:

import "@gunjo/ui/styles";
import "./globals.css";

5. 最初のコンポーネント

app/page.tsx:

import { Button, Card, CardHeader, CardContent } from "@gunjo/ui";

export default function Page() {
  return (
    <main className="p-8">
      <Card>
        <CardHeader>
          <h2 className="text-xl font-semibold">GunjoUI が動いている</h2>
        </CardHeader>
        <CardContent>
          <Button>Primary</Button>
          <Button variant="secondary">Secondary</Button>
        </CardContent>
      </Card>
    </main>
  );
}

npm run dev で Button が GunjoUI のスタイルで表示されれば成功。

Tailwind を使わないプロジェクト(純 CSS サブパス)

npm 不可環境向けに固定 URL で配布している ⁠Tailwind 非依存の純 CSS 資産⁠ は、パッケージにも同梱しており subpath で import できる:

@import "@gunjo/ui/tokens.css";    /* 純 CSS トークン(:root / .dark。hsl(var(--…)) 記法) */
@import "@gunjo/ui/patterns.css";  /* gj- パターンクラス(card / badge / button / table / tabs / timeline / gantt / meter 等) */

JS からの import "@gunjo/ui/tokens.css"; でもよい(bundler が CSS import を扱える構成の場合)。

  • ⁠@gunjo/ui/styles との違い⁠:styles(dist/globals.css)は Tailwind 前提のフル定義で、コンポーネント(React)利用時はこちら。tokens.css / patterns.css は Tailwind の無いプロジェクトで GUNJO のトークンと基本パターンだけ使いたい場合に選ぶ
  • 中身は gunjo.jp/tokens.css / gunjo.jp/patterns.css の配信版と同一(同じソース・オブ・トゥルースから生成し drift 検証つき)。npm も使えない環境では固定 URL をコピペする(/docs/no-npm 参照)
  • ⁠公開状況⁠:0.1.0-beta.2 から収録済み(npm 版でそのまま import できる)

Server Component からのバレル import(RSC)

0.2.0 からは、Server Component(layout.tsx / page.tsx など)から import { TooltipProvider } from "@gunjo/ui" しても、そのまま next build が通る。CI(design-verify)が変更のたびに、npm pack した tarball を空の Next.js App Router アプリに入れ、Turbopack と webpack の両方で next build して確かめている(npm run lib:check:rsc-consumer。重い部品の optional peer は入れない状態・transpilePackages なし)。

経緯(#684)

0.1.0-beta.1 と Next.js 16.2.10(Turbopack)で、Server Component からバレル import すると next build の Collecting page data 段階で失敗するという報告があった(2026-07-24・#684):

TypeError: i.createContext is not a function

同じ手順を 2026-09-22(7通り)と 2026-10-11(0.1.0-beta.1・0.1.0-beta.4・0.2.0 の形 × Turbopack・webpack)に試したが、報告された版でも再現しなかった。当時の条件は再現できず、0.2.0 の形で上の検査が通ることを確かめて #684 を閉じた。

それでも同じエラーが出たら

Next.js の版・next.config・落ちたファイルを添えて #684 に報告してほしい。その間は、利用側に "use client" を付けた再エクスポートを 1 枚作り、アプリからの import をそこ経由にすると通る(シム自体が client 境界になる):

// components/ui.ts
"use client";
export {
  Button,
  Card,
  CardHeader,
  CardContent,
  TooltipProvider,
  // 使うコンポーネントを列挙
} from "@gunjo/ui";
// app/layout.tsx(Server Component のまま)
import { TooltipProvider } from "@/components/ui";

Server Components と関数prop(RSC)

一部のコンポーネントは ⁠関数の prop⁠(formatValue / formatTime / renderCard / renderNode など)を受け取る。これらを ⁠Server Component から直接渡すと next build が失敗する⁠:

Error: Functions cannot be passed directly to Client Components
unless you explicitly expose it by marking it with "use server".

これは React の制約で、関数はサーバー→クライアント境界をまたげないため。tsc --noEmit も next dev も気づかず、⁠next build(本番ビルド)だけが検出する⁠ので、最初の本番ビルドで初めて踏みがち。

⁠対処(いずれか)⁠

  1. ⁠既定のまま使う⁠ — 関数 prop を渡さなければどのコンポーネントも RSC で安全に描画できる(既定パスはサーバー安全)。

  2. ⁠シリアライズ可能な代替を使う⁠ — 数値整形の主要コンポーネントは、関数の代わりに valueFormat("number" | "compact" | "integer" または Intl.NumberFormatOptions)を受け取る。これは serializable なので Server Component から渡せる:

    // Server Component — OK(関数ではなく serializable な指定)
    <PieChart segments={data} valueFormat="compact" />
    <GaugeChart value={72} valueFormat={{ style: "currency", currency: "JPY" }} />
    
  3. ⁠クライアント境界で包む⁠ — 関数整形や JSX を返したい場合は、"use client" を付けた薄いラッパーに切り出し、そこから関数 prop を渡す:

    "use client";
    import { PieChart } from "@gunjo/ui";
    export function RevenuePie({ data }: { data: { label: string; value: number }[] }) {
      return <PieChart segments={data} formatValue={(n) => `¥${n.toLocaleString()}`} />;
    }
    

どのコンポーネントが関数 prop を持つかは各コンポーネントの docs(Props 表)で確認できる。valueFormat 等の serializable 代替は順次追加中(#576)。

Dark Mode 有効化

GunjoUI は CSS variables ベースで、html または body に class="dark" を付けるだけで全コンポーネントが dark token に切り替わる。採用先で next-themes などのライブラリと組み合わせる場合は、採用先プロジェクトに明示的に追加する:

npm install next-themes

app/layout.tsx:

import { ThemeProvider } from "next-themes";

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

GunjoUI 本体には ThemeProvider / ThemeToggle も含まれているため、外部ライブラリを使わずに GunjoUI の .dark class 管理だけで始めることもできる。

⁠L3 段階の注記⁠:dark mode 全 70 コンポーネントの目視通しキャプチャは未取得。docs サイト(npm run dev → :13030)でトグル切替して目視確認することを推奨。

フォント前提

GunjoUI のテキスト系コンポーネントは Inter を fontFamily に指定している。

  • ⁠Next.js⁠:next/font/google の Inter を root layout で読み込めば OK
  • ⁠その他⁠:採用先の CSS で @import url('https://fonts.googleapis.com/css2?family=Inter...') を読む

和文(日本語)は GunjoUI 側で OS フォールバック前提。明示したい場合は採用先の CSS で font-family: Inter, "Hiragino Sans", "Yu Gothic UI", sans-serif; などを設定。

トラブルシューティング

SyntaxError: Unexpected token でビルドが落ちる

0.0.1-alpha.2 以前の生 TS 配布版を掴んでいる可能性が高い。最新版はコンパイル済み dist/ を配布しており transpilePackages 不要(§2 ビルド設定)。パッケージを更新するか、旧版なら next.config.ts に transpilePackages: ["@gunjo/ui"] を追加する。

Tailwind クラスが効かない

v3 の場合は tailwind.config.ts の content に node_modules/@gunjo/ui/dist/**/*.js を入れ忘れている可能性が高い。v4 の場合は @source ディレクティブで同等のパスを指す必要がある。Tailwind は採用先のクラス出現箇所しかスキャンしないため、library のクラスも明示する必要がある。

色が真っ黒・真っ白

@gunjo/ui/styles の import が抜けている、または順序が @import "tailwindcss" の ⁠後⁠ にきていない。CSS variables が定義されていないと bg-background などのクラスが空になる。

Tailwind v4 で動かない

本リポジトリの docs サイトは v4 + Next 16 で稼働確認済(dependencies.md の ✅ 行)。v4 で問題が出る場合は最初に @config のパス解決を疑う(採用先の globals.css から見た相対パスが正しいか)。それでもだめなら issue で報告。

createContext is not a function でビルドが落ちる

0.2.0 以降は CI で出ないことを確かめている(§ Server Component からのバレル import)。出たら #684 に報告し、その間は同じ節の "use client" 再エクスポートで通す。

Functions cannot be passed directly to Client Components でビルドが落ちる

Server Component から関数 prop(formatValue 等)を渡している。tsc / next dev は通り next build だけが落ちる。§ Server Components と関数prop の対処(valueFormat を使う/"use client" ラッパーで包む)を参照。

次のステップ