HonoX上でshadcnを動かしてみた
はじめに
こんにちは!satto workspaceでプロダクトエンジニアをしている ryohei oyama(@ryohei_oyama)です。
HonoXでshadcn/uiを使いたい!でも設定どうするの...?
実はTailwind設定とaliasを設定するだけで動きます。この記事ではその手順を解説します。
セットアップ手順
1. プロジェクト作成
npm create hono@latest my-app
対話形式で進みます:
- テンプレート選択で
x-basicを選択 - 他はデフォルトでOK
cd my-app
npm install
2. React 19を追加
HonoXのx-basicテンプレートにはReactが含まれていないため、追加します。
npm install react react-dom
npm install -D @types/react @types/react-dom
3. Tailwind CSS v4を追加
npm install tailwindcss @tailwindcss/vite
4. Vite設定でTailwindとaliasを設定
vite.config.tsを以下の内容で作成:
import build from '@hono/vite-build/node'
import honox from 'honox/vite'
import adapter from '@hono/vite-dev-server/node'
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
import path from "path"
export default defineConfig(({ mode }) => {
if (mode === 'client') {
return {
build: {
rollupOptions: {
input: ['./app/client.ts', './app/style.css'],
output: {
entryFileNames: 'static/client.js',
chunkFileNames: 'static/assets/[name]-[hash].js',
assetFileNames: 'static/assets/[name].[ext]'
}
},
emptyOutDir: false
},
plugins: [tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./app"),
},
},
}
} else {
return {
ssr: {
external: ['react', 'react-dom']
},
plugins: [
honox({
devServer: { adapter },
client: { input: ['./app/style.css'] }
}),
tailwindcss(),
build()
],
resolve: {
alias: {
"@": path.resolve(__dirname, "./app"),
},
},
}
}
})
ポイント:
-
mode === 'client'でクライアントビルドとサーバービルドを分岐 -
tailwindcss()プラグインを両方のモードで追加 -
@エイリアスを./appに設定 -
ssr.externalでReactを外部化(SSRで重複読み込みを防ぐ)
5. TypeScript設定
tsconfig.jsonにReact設定とパスエイリアスを追加:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"jsxImportSource": "react",
"baseUrl": ".",
"paths": {
"@/*": ["./app/*"]
}
}
}
ポイント:
-
jsx: "react-jsx"- React 17以降の新しいJSX変換を使用 -
jsxImportSource: "react"- JSXのインポート元を明示
6. Reactクライアント設定
HonoXでReact 19を使うためにapp/client.tsを作成:
import { createClient } from 'honox/client'
createClient({
hydrate: async (elem, root) => {
const { hydrateRoot } = await import('react-dom/client')
hydrateRoot(root, elem)
},
createElement: async (type: any, props: any) => {
const { createElement } = await import('react')
return createElement(type, props)
}
})
7. レンダラー設定
app/routes/_renderer.tsxを作成してCSSを読み込む:
import { reactRenderer } from '@hono/react-renderer'
export default reactRenderer(({ children }) => {
return (
<html lang="ja">
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{import.meta.env.PROD ? (
<>
<script type="module" src="/static/client.js"></script>
<link href="/static/assets/style.css" rel="stylesheet" />
</>
) : (
<>
<script type="module" src="/app/client.ts"></script>
<link href="/app/style.css" rel="stylesheet" />
</>
)}
</head>
<body>{children}</body>
</html>
)
})
ポイント:
-
import.meta.env.PRODで開発環境と本番環境を分岐 - 開発時は
/app/style.css、本番時は/static/assets/style.cssを読み込む
8. CSS変数の定義
app/style.cssを作成:
@import "tailwindcss";
shadcn/uiを使う
1. 初期化
npx shadcn@latest init
設定のポイント:
- Style: お好みで(New YorkまたはDefault)
- Base color: お好みで
- CSS variables:
yes - CSSパスは
app/style.cssに設定
2. コンポーネント追加
npx shadcn@latest add button
これだけ!app/components/ui/button.tsxが生成されます。
完成したディレクトリ構成
.
├── app/
│ ├── components/
│ │ └── ui/
│ │ └── button.tsx # shadcn/uiのButtonコンポーネント
│ ├── lib/
│ │ └── utils.ts # cn()ユーティリティ
│ ├── routes/
│ │ ├── _renderer.tsx # レイアウト
│ │ └── index.tsx # トップページ
│ ├── client.ts
│ ├── global.d.ts
│ ├── server.ts
│ └── style.css # Tailwind CSS + CSS変数
├── components.json # shadcn/ui設定
├── package.json
├── tsconfig.json # TypeScript設定
└── vite.config.ts # Vite設定(alias + Tailwind)
使ってみる
app/routes/index.tsxで使用:
import { createRoute } from 'honox/factory'
import { Button } from '@/components/ui/button'
export default createRoute((c) => {
return c.render(
<div className='flex gap-2 p-4'>
<Button>デフォルト</Button>
<Button variant="secondary">セカンダリ</Button>
<Button variant="outline">アウトライン</Button>
</div>
)
})
npm run dev
これで完了です!

shadcn/uiのButtonコンポーネントが動作している様子
よくあるエラー
パスエイリアスが解決されない
Cannot find module '@/components/ui/button'
→ vite.config.tsとtsconfig.json両方にaliasを追加してください。
スタイルが効かない
→ app/style.cssにTailwindの@import "tailwindcss"があるか確認してください。
まとめ
HonoXでshadcn/uiを使うには:
- Tailwind CSS v4のViteプラグインを追加
-
パスエイリアス
@/*を設定(Vite + TypeScript) - CSS変数を定義
これだけでshadcn/ui CLIが使えます。サクッと設定して、美しいUIコンポーネントを使いましょう!
余談
私の理解不足かもしれませんが、Aceternity UIのコンポーネントも試してみたところ、アニメーション系が全然動きませんでした...
shadcn/uiのようなシンプルなスタイリングベースのコンポーネントは問題なく動作しますが、framer-motionなどを使った複雑なアニメーションは難しそうです。そもそもHonoXは作者のyusukebeさんの記事にもある通り「インタラクションの少ないWebサイト」向けのMPAフレームワークなので、納得の結果でした。
Discussion