0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【shadcn/ui】npx shadcn@latest add comboboxが使えなかった

Last updated at Posted at 2025-08-27

はじめに:shadcn/uiとは何か?

shadcn/ui は、Radix UI のアクセシブルなコンポーネントを Tailwind CSS で構成し、React/Next.js プロジェクトに導入できる UI ライブラリです。
特徴は以下の通りです:

  • CLI (npx shadcn add <component>) を使って必要なコンポーネントを簡単に追加できる
  • 各コンポーネントは「ソースコードのコピー」として導入されるため自由にカスタマイズ可能
  • 公式が提供するのは 完成品のライブラリではなく、コピー元の設計リソース

直面した問題:npx shadcn@latest add combobox が動かない

公式サイトには Combobox のドキュメント が存在しますが、実際に以下を実行するとエラーになります。

npx shadcn@latest add combobox
It may not exist at the registry. Please make sure it is a valid component.

これは CLI に combobox が登録されていない ためです。
GitHub Issue などでも同様の報告(投稿はsvelteですが...)が見られます。
shadcn-svelte issue #1520

なぜ動かないのか?

公式ドキュメント にもある通り、combobox は独立したコンポーネントではなく、以下を組み合わせて実装する「Composite Component(複合コンポーネント)」です。

そのため CLI では直接インストールできず、自分でファイルを作成してコードを貼り付ける必要があります。


解決方法:comboboxを導入する手順

1. 初期化

まず Shadcn UI を初期化します。※すでに導入済の場合は不要です

npx shadcn@latest init

詳細: CLI ドキュメント


2. 必要なコンポーネントを追加

combobox 構築に必要な部品を導入します。

npx shadcn@latest add popover command

これで components/ui/ 配下に popover.tsxcommand.tsx が追加されます。

3. 実用例(props対応)

components/ui/ 配下に以下のファイルを新規作成します。
汎用的に利用するため、元記事のソースコードを少し編集(props対応)しています。

combobox.tsx
"use client"

import * as React from "react"
import { Check, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"

type Option = {
  value: string
  label: string
}

type ComboboxProps = {
  options: Option[]
  placeholder?: string
  emptyText?: string
  onChange?: (value: string) => void
}

export function Combobox({
  options,
  placeholder = "Select option...",
  emptyText = "No results found.",
  onChange,
}: ComboboxProps) {
  const [open, setOpen] = React.useState(false)
  const [value, setValue] = React.useState("")

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button variant="outline" role="combobox" aria-expanded={open}>
          {value
            ? options.find((o) => o.value === value)?.label
            : placeholder}
          <ChevronsUpDown className="ml-2 h-4 w-4 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-[200px] p-0">
        <Command>
          <CommandInput placeholder="Search..." />
          <CommandEmpty>{emptyText}</CommandEmpty>
          <CommandList>
            <CommandGroup>
              {options.map((o) => (
                <CommandItem
                  key={o.value}
                  value={o.value}
                  onSelect={(val) => {
                    setValue(val)
                    setOpen(false)
                    onChange?.(val)
                  }}
                >
                  {o.label}
                  {value === o.value && <Check className="ml-auto" />}
                </CommandItem>
              ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  )
}

4. 呼び出し例

<Combobox
  options={[
    { value: "next.js", label: "Next.js" },
    { value: "sveltekit", label: "SvelteKit" },
    { value: "nuxt.js", label: "Nuxt.js" },
  ]}
  placeholder="フレームワークを選択してください"
  onChange={(val) => console.log("選択:", val)}
/>

まとめ

  • npx shadcn add combobox は執筆時点(2025/08/27)で利用不可
  • combobox は Popover + Command を組み合わせた複合コンポーネント
  • 解決策:npx shadcn add popover command 実行後→ combobox.tsx ファイルを自分で準備する必要がある
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?