PixelDosa UI

Parameter Panel

The controls beside the prompt — pick a look from previews instead of naming it.

Settings

Look

Real lighting and depth of field. Best for product shots.

Shape
How many

4 photographic square · 40 credits

Installation

bash
npx shadcn@latest add @pixeldosa/parameter-panel

Requires `cn` at `@/lib/utils`. Give every option a real `preview` where you can — a thumbnail of that style, a shape for an aspect ratio — and never ship an option that is only an icon.

Usage

"use client";

import { ParameterPanel } from "@/components/ui/parameter-panel";

<ParameterPanel
  groups={groups}
  values={values}
  onChange={(groupId, optionId) => setValues({ ...values, [groupId]: optionId })}
  summary="4 photographic square images · 40 credits"
  onReset={reset}
/>

Why it exists

Research on generative tools calls the core problem the articulation barrier: people can picture what they want but can't name it, and style vocabulary ("tilt-shift", "synth-wave") is exactly the knowledge they lack. Showing options beats asking people to describe them.

Features

  • Recognition, not recall. Every option can carry a small preview: a thumbnail of that style, a shape for an aspect ratio.
  • Labels always ship. Studies of prompt controls found novel icons are misread almost universally, so an option is never an icon alone.
  • Price on the option. Anything that changes the cost says so where it's chosen, not in a bill afterwards.
  • One help line per group, under the current choice, instead of help text on every option.
  • Real radio groups. Arrow keys, grouping and announcement come from the platform.

Props

PropTypeNotes
groups{ id, label, options }[]Options carry label, preview?, costNote?, detail?.
valuesRecord<string, string>Chosen option id per group id.
onChange(groupId, optionId) => voidRequired.
summarystringWhat the choices add up to.
onReset() => void
titlestringDefaults to "Settings".
headingLevel2 | 3 | 4 | 5 | 6Defaults to 3.

Accessibility

  • Each group is a fieldset with a legend; options are radio inputs, so arrow keys work and the group is announced as a group.
  • Previews are decorative and hidden; the label is the accessible name.
  • Focus shows the standard ring on the whole option, not just the hidden input.

When not to use

  • A settings page. This belongs beside the thing it affects.
  • Free-text parameters: put those in Prompt Composer's controls.
  • Twenty options in a group: that's a picker or a search, not a row of previews.

why it's built this way

Engineering Notes

Each group is a real `fieldset` of radio inputs with the input visually hidden behind its label, so arrow-key navigation, grouping and announcement come from the platform rather than from a custom roving-tabindex implementation that would have to be re-tested in every host app. The chosen value is caller-owned per group id, which lets a product persist presets, share them in a URL, or drive them from a model's suggestion without the component holding a second source of truth. `costNote` sits on the option rather than being derived, because only the caller knows how its pricing composes — quality multiplied by count multiplied by resolution is not something a component can infer from labels. `detail` renders once per group under the current choice instead of on every option, which keeps a panel of twelve options from becoming a wall of help text.

how it moves, and when it doesn't

Motion Notes

Nothing animates beyond the standard instant colour change on a choice. Selection is carried by border weight and label weight rather than motion: this is the user's turn, and a panel that animates under a moving cursor invites mis-clicks. Under `prefers-reduced-motion` even those transitions are dropped.