Preference pairPro
Two images side by side to train a personal style. 1 or 2 picks the better one, T marks a tie, S skips and Z takes it back, with progress toward a style profile.
On this page
ProRate pairs to train a personal style: 1 or 2 picks, T ties, S skips, Z undoes. Four more ratings unlock the profile.
Installation
Usage
import { PreferencePair } from "@/components/ui/chatcn/pro/preference-pair"
<PreferencePair
pairs={pairs}
rated={profile.ratings}
goal={40}
onChoose={(choice, pair) => api.rate(pair.id, choice)}
onUndo={(choice, pair) => api.unrate(pair.id)}
onLoadMore={fetchMorePairs}
/>pairs is a queue: append to it and rating carries on. Ratings count toward goal (skips do not); when the goal is reached the header turns to Profile ready and the milestone is announced. The next two pairs are preloaded so a pick swaps to decoded images.
When the queue runs out, loading shows a placeholder pair; otherwise the finished state says how many ratings are left and offers onLoadMore, or onProfileOpen once the profile is ready.
Examples
States
Loading the next pair, an image that failed to load, a finished queue, a ready profile, nothing to rate, disabled and right to left.
ProLoading the next pair, a failed image, a finished queue, a ready profile, nothing to rate and disabled.
Props
| Prop | Type | Notes |
|---|---|---|
pairs | PreferencePairItem[] | Required. id, a, b and an optional prompt |
onChoose | (choice: "a" | "b" | "tie" | "skip", pair) => void | Every choice, skips included |
onUndo | (choice, pair) => void | The last choice was taken back |
rated | number | Ratings made before this session. Default 0 |
goal | number | Ratings a profile needs. Default 40 |
loading | boolean | More pairs are on the way |
onLoadMore, onProfileOpen | () => void | Actions in the finished state |
aspect | number | Width over height of both frames. Default 4 / 5 |
question | string | Default "Which image do you prefer?" |
hotkeys | "scoped" | "global" | "off" | Default scoped to [data-hotkey-scope] |
disabled | boolean |
Keyboard
| Key | Action |
|---|---|
1, 2 | Prefer the first or the second image (start and end, so right to left keeps 1 first) |
T | A tie: both are as good |
S | Skip the pair without rating it |
Z or Backspace | Take back the last choice |
Accessibility
- Each image is a button named from its visible number, "1, prefer this image", and described by its alt text.
- The training progress is a
progressbarwith the count in words. Every choice and the milestone are announced politely. - Shortcuts never fire while typing in a field. An image that fails to load says so and offers a retry; it cannot be picked.
Motion
- The pick never animates: its ring and mark show at once and hold for 180 ms so you see what was recorded.
- Picked with a pointer, the next pair fades in over 200 ms; from the keyboard it swaps instantly, because rating is done hundreds of times.
- The progress fill eases over 300 ms and jumps under reduced motion.