KQ-1759 · SIMILAR/IDEAS

Similar Ideas

An idea panel that checks the roadmap while you type: after three letters a quiet spinner turns at the end of the field, then the ideas most like yours rise 16px from below it on springs.glide in cascade order, each with its status, votes and a match strength that fills as it lands; ideas that stop matching fade out and the rest glide to their seats. Voting folds your draft into the idea as your comment — the draft lifts off the field as a pill and glides into the row's note line while the vote count rolls on snap and the comment badge lands on recoil — and with nothing similar the list gives way to a clean submit. The field is a combobox: Up and Down move through matches, Enter votes, Shift+Enter follows and Escape clears.

KQ-1759 · SIMILAR/IDEAS

Suggest an idea

Coldbrook roadmap · 14 ideas · 4 planned

Similar ideas appear as you type

Up and Down move through similar ideas, Enter votes for the highlighted one and adds your text as a comment, Shift with Enter follows it, Escape clears.

empty field · 14 ideas

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/similar-ideas

Props

ideas / defaultIdeas
SimilarIdea[]
default — / defaultSimilarIdeas
The roadmap's ideas as { id, title, body, status: "review" | "planned" | "shipped", votes, comments, voted?, following?, updated, shippedIn?, note? }, controlled or initial.
onIdeasChange
(ideas: SimilarIdea[]) => void
default —
Fires with every idea after a vote, a follow or a post.
value / defaultValue
string
default — / ""
The draft title in the field, controlled or initial.
onValueChange
(value: string) => void
default —
Fires on every keystroke, and when a vote or a post clears the field.
onVote
(ideaId: string, voted: boolean, comment?: string) => void
default —
A vote was cast (with the draft as the comment when there was one) or taken back.
onSubmitNew
(idea: { title: string; details: string }) => void
default —
Post was pressed: a new idea from the field and the details.
onFollow
(ideaId: string, following: boolean) => void
default —
The follow bell was pressed, or Shift+Enter on a highlighted match.
onMatches
(ideaIds: string[]) => void
default —
A search settled, with the ids of the similar ideas it found — for counting requests that found an existing home.
matchStyle
"bar" | "dots" | "ring"
default "bar"
How the match strength reads: a thin bar with its percentage, five dots, or a small ring gauge.
density
"compact" | "regular" | "roomy"
default "regular"
Row height, padding, gaps and type.
statusPalette
"signal" | "cool" | "mono"
default "signal"
Status colours: amber, cobalt and green; three cool hues; or ink, with the dashed, half and filled glyphs telling them apart.
maxMatches
number
default 4
The most similar ideas shown at once.
minScore
number
default 0.2
How alike an idea must be to show, from 0 to 1.
searchDelayMs
number
default 320
How long the quiet spinner turns after the last keystroke before matches rise, in ms.
product
string
default "Coldbrook"
The product whose roadmap this is, named in the header.
placeholder
string
default "Describe your idea in a line"
The field's placeholder.
now
number | Date
default defaultSimilarIdeasNow
The moment ages count from, so the server and the browser print the same text.
status
"ready" | "loading" | "error"
default "ready"
Whether the ideas have arrived: loading holds the field, error shows a line with Try again.
onRetry
() => void
default —
Try again was pressed after the ideas failed to load.
maxHeight
number
default 540
Tallest the panel grows before it scrolls inside, in px.
disabled
boolean
default false
Nothing can be typed, voted, followed or posted.
className
string
default —
Classes for the panel.