Zenn
💬

shadcn/ui CLIに対応したReactコンポーネントの作り方

2025/02/27に公開
1

先日、Builders Weekendハッカソンにパートナーとして参加したことをきっかけに、shadcn/ui CLIに対応したReactコンポーネントを開発しました。その際の開発体験が素晴らしかったので、開発手順の解説と、おすすめポイントをお伝えしたいと思います!

作ったコンポーネント集は👇です。Vercel AI SDKと組み合わせて使うことで、LLM APIを用いたアプリを素早く開発することができます。

https://www.agents-kit.dev/

import * as React from "react"
import { useChat } from '@ai-sdk/react'
import { ChatForm } from '@/components/agents-kit/chat-form';

export function ChatFormDemo() {
  const { input, handleInputChange, handleSubmit } = useChat({});

  return (
    <ChatForm 
      inputValue={input} 
      onInputChange={handleInputChange} 
      onSubmit={handleSubmit} 
    />
  )
}

https://ui.shadcn.com/

TL;DR

作り方

  1. Next.jsプロジェクトを始める。配布したいReactコンポーネントは /registry ディレクトリで開発する。
  2. コンポーネントが完成したら、 registry.json を書いて配布設定をする。
  3. shadcn build で、コンポーネントごとのJSONファイルをビルドする。publicディレクトリに出力される。
  4. Next.jsプロジェクトをデプロイし、JSONファイルを公開する。Next.jsプロジェクトはそのままドキュメントサイトとして開発するのがおすすめ。

良かったこと

  • 通常のReactプロジェクトとして開発できること。コンポーネントライブラリとしてのバンドルをしなくていいので、手軽にスタートできる。
  • 依存パッケージの管理がよくできている。コンポーネントのインストール時に必要なnpmパッケージや、 shadcn/uiのコンポーネントが自動的にインストールされるのが便利。

開発手順

Reactプロジェクトを初期化し、コンポーネントを開発する

Next.jsまたはViteでReactプロジェクトをスタートします。shadcn/ui CLI向けのコンポーネント開発は、通常のReactプロジェクトとなんら変わりない手順で開発をスタートできます。

コンポーネントの開発は特別な点はありませんが、shadcn/ui CLIを使うユーザーは間違いなくTailwindCSSを導入しているので、スタイリングは当然TailwindCSSを使います。

以下は、Agents Kitで実際に配布している ChatForm というコンポーネントの例です。

// registry/agents-kit/chat-form.tsx
"use client";

import React, { FC, KeyboardEvent, PropsWithChildren, useRef } from "react";
import { AutosizeTextarea } from "./autosize-textarea";
import { ChatActionIconButton, ChatActions } from "./chat-actions";
import { Button } from "@/components/ui/button";
import { LucideArrowUp, LucidePlus } from "lucide-react";
import { Card } from "@/components/ui/card";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

export interface ChatFormProps {
  inputValue?: string;
  onInputChange?: (
    e:
      | React.ChangeEvent<HTMLInputElement>
      | React.ChangeEvent<HTMLTextAreaElement>
  ) => void;
  onFileChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
  onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
  actions?: React.ReactNode;
}

const ChatForm: FC<PropsWithChildren<ChatFormProps>> = (props) => {
  return (
    <Card className="p-2 rounded-3xl shadow">
      <form onSubmit={props.onSubmit} className="grid grid-cols-1 gap-2">
        {props.children}
        {/* 中略 */}
        </ChatActions>
      </form>
    </Card>
  );
};

export { ChatForm };

registry.jsonを書く

プロジェクトルートにregistry.jsonファイルを作成し、ドキュメントを参考に設定を書きます。ポイントは以下です。

  • npmパッケージの依存は dependencies に記載
  • shadcn/ui CLI互換の依存は、 registryDependencies に記載

registryDependencies があることで、shadcn/uiのコンポーネントや、自作のshadcn/ui CLI対応のコンポーネントへの依存を管理できます。

{
    "$schema": "https://ui.shadcn.com/schema/registry.json",
    "name": "Agents Kit",
    "homepage": "https://agents-kit.dev",
    "items": [
        ...
        {
    	    "name": "chat-form",
    	    "type": "registry:component",
    	    "title": "Chat Form",
    	    "description": "A chat form component.",
    	    "dependencies": ["lucide-react"],
    	    "registryDependencies": [
    	      "card", 
    	      "dropdown-menu", 
    	      "https://agents-kit.dev/r/autosize-textarea.json", 
    	      "https://agents-kit.dev/r/chat-actions.json"
    	    ],
    	    "files": [
                {
                    "path": "src/registry/agents-kit/chat-form.tsx",
                    "type": "registry:component",
                    "target": "components/agents-kit/chat-form.tsx"
                }
            ]
        },
        ...
    ]
}

component.jsonをビルド

shadcn build コマンドで、component.jsonファイルをビルドします。この例では、 public/r/chat-form.json が生成されます。

{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chat-form",
  "type": "registry:component",
  "title": "Chat Form",
  "description": "A chat form component.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "card",
    "dropdown-menu",
    "https://agents-kit.dev/r/autosize-textarea.json",
    "https://agents-kit.dev/r/chat-actions.json"
  ],
  "files": [
    {
      "path": "src/registry/agents-kit/chat-form.tsx",
      "content": "\"use client\";\n\n ...",
      "type": "registry:component",
      "target": "components/agents-kit/chat-form.tsx"
    }
  ]
}

この状態でプロジェクトをデプロイすると、以下のようなコマンドが通るようになります。

npx shadcn@latest add http://agents-kit.dev/r/chat-form.json

Reactプロジェクトをドキュメントサイトとして開発する

これで配布手順は完了です!が、component.jsonを公開するために、どうせプロジェクトをデプロイすることになるので、Reactプロジェクトをそのままドキュメントサイトとして開発することをおすすめします!

良かった点

依存管理が充実している

前述のように、 registry.json の中で、npmパッケージや他の component.json への依存を管理ことができます。これにより、開発と配布の手軽さと、ユーザーサイドの実用性が両立されているように思います。

コンポーネントのインストール時に必要な依存関係が自動でインストールされるので、非常に便利です。

npmパッケージだけでなく他の component.json への依存が表現できるため、npmへの公開を経由せずにコンポーネントを配布することができます。コミュニティが盛り上がることで、よりパワフルなツールキットになっていくと思います!

チーム内でコンポーネントライブラリを共有したいときに、手軽にスタートできる

npmへの公開を経由せずにコンポーネント配布できることから、チーム内でコンポーネントライブラリを配布・共有する手段として素晴らしい選択肢だと感じました。npmやGithub packagesなどの代替手段に比べて大幅に気軽ながら、コンポーネントの配布だけで考えれば十分な機能が実現されていると思います。

1

Discussion

ログインするとコメントできます