Model Selector

AI & Chat

AI model selection dropdown.

Preview

Usage

example.jsx
import { ModelSelector } from "@/components/ui/model-selector";

export default function Example() {
  return <ModelSelector />;
}

Source Code

Copy this file into components/ui/model-selector.jsx in your project.

model-selector.jsx
"use client";

import { forwardRef, useState } from "react";
import { cn } from "@/lib/utils";

const ModelSelector = forwardRef(({ className, models = [], value, onChange, ...props }, ref) => {
  const [open, setOpen] = useState(false);
  const selected = models.find((m) => m.id === value) || models[0];

  return (
    <div ref={ref} className={cn("relative", className)} {...props}>
      <button onClick={() => setOpen(!open)}
        className="inline-flex items-center gap-2 rounded-lg border px-3 py-1.5 text-sm font-medium transition-colors hover:bg-accent"
      >
        {selected?.icon && <span>{selected.icon}</span>}
        <span>{selected?.name || "Select model"}</span>
        <svg className={cn("h-3.5 w-3.5 transition-transform", open && "rotate-180")} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
      </button>
      {open && (
        <div className="absolute left-0 top-full z-50 mt-1 w-64 rounded-lg border bg-popover p-1 shadow-lg">
          {models.map((m) => (
            <button key={m.id} onClick={() => { onChange?.(m.id); setOpen(false); }}
              className={cn("flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-sm transition-colors hover:bg-accent",
                m.id === value && "bg-accent"
              )}
            >
              {m.icon && <span className="text-lg">{m.icon}</span>}
              <div className="flex-1 min-w-0">
                <div className="font-medium">{m.name}</div>
                {m.description && <div className="truncate text-xs text-muted-foreground">{m.description}</div>}
              </div>
              {m.id === value && <svg className="h-4 w-4 shrink-0 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>}
            </button>
          ))}
        </div>
      )}
    </div>
  );
});
ModelSelector.displayName = "ModelSelector";

export { ModelSelector };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge