quiz-ui
componentquiz-image-choicesource: ok · hit
QuizImageChoice
Visual/image-based single-select answer grid.
npx shadcn add "https://quiz-ui-phi.vercel.app/r/quiz-image-choice.json"free
Interaction
dropdown
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightui-primitives@radix-ui/react-radio-group
Registry dependencies
@quiz-ui/quiz-core@quiz-ui/quiz-cn
Files1 · source cached 10/8/2026, 6:47:36 PM
components/ui/quiz/quiz-image-choice.tsx
"use client";
import * as React from "react";
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import { useQuizAnswers } from "./core";
export interface QuizImageChoiceOption {
value: string;
label: string;
imageUrl: string;
}
export interface QuizImageChoiceProps {
options: QuizImageChoiceOption[];
/** Applied to the grid wrapper — column count is now entirely your responsibility via className. */
className?: string;
itemClassName?: string;
activeItemClassName?: string;
imageClassName?: string;
labelClassName?: string;
}
export function QuizImageChoice({
options,
className,
itemClassName,
activeItemClassName,
imageClassName,
labelClassName,
}: QuizImageChoiceProps) {
const { value, setValue } = useQuizAnswers();
return (
<RadioGroupPrimitive.Root
className={className}
value={typeof value === "string" ? value : undefined}
onValueChange={setValue}
>
{options.map((option) => {
const isOn = value === option.value;
return (
<RadioGroupPrimitive.Item
key={option.value}
value={option.value}
className={isOn && activeItemClassName ? `${itemClassName ?? ""} ${activeItemClassName}` : itemClassName}
>
<img src={option.imageUrl} alt={option.label} className={imageClassName} />
<span className={labelClassName}>{option.label}</span>
</RadioGroupPrimitive.Item>
);
})}
</RadioGroupPrimitive.Root>
);
}