KQ-2050 · SPUR/COLUMNS

Spur Columns

An assistant thread where any phrase becomes its own column: choose a dotted phrase in an answer, or select any words and ask about them, and the phrase is lifted out as a chip and carried to the new column's header on springs.glide — landing exactly, because the destination comes from the computed layout rather than a mid-flight measure — while the new column grows in and the older ones narrow to readable spines on the same spring. Every column has its own skeleton, empty and failed states and its own follow-up composer, answered through answerFor (which may return a promise). Left and Right walk the columns, Escape folds the rightmost back into its phrase on the exit ease and returns focus there, and under 520px the columns become a stack that follows a sideways swipe 1:1, rubber-bands at the ends and commits by projection with the trail shown as chips.

KQ-2050 · SPUR/COLUMNS

Left and Right walk the columns. Escape folds the rightmost column back into its phrase.

Question

Fernworks onboarding

  1. How do I get my team set up on Fernworks?

    Start by creating a workspace and choosing workspace roles2 for the people you invite. Guest seats are free for clients who only need to comment. If your company signs in with SSO, connect it before you invite anyone so accounts are created the right way. Then import your boards from spreadsheets or another tool, and work through the onboarding checklist in the sidebar; it takes about twenty minutes.

From Fernworks onboarding

workspace roles

  1. Fernworks has three roles. Admins manage billing, SSO and who can join. Members create and edit boards in any team they belong to. Viewers can read and comment but not edit. Change a role any time from Members in settings, and a team can override it for its own boards.

ready · 2 columns · active: workspace roles

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/spur-columns

Props

columns / defaultColumns
SpurColumn[]
default — / defaultSpurColumns
Columns left to right, controlled or initial: { id, phrase?, parentId?, turns: { id, prompt, status: "loading" | "ready" | "empty" | "failed", answer?: { text, phrases? } }[] }.
onColumnsChange
(columns) => void
default —
Fires with every column after an open, a fold, an ask or an arriving answer.
answerFor
(prompt, context) => SpurAnswer | null | Promise<…>
default defaultSpurAnswerFor
Answers a spur's phrase or a follow-up ({ columnId, phrase?, kind: "spur" | "ask" }). null shows the empty state; a rejected promise shows the failed state with Try again.
onAsk
(text, columnId) => void
default —
A follow-up was asked in a column's composer.
onOpenSpur
(phrase, fromColumnId, column) => void
default —
A spur was opened from a suggested phrase or a selection.
onCloseSpur
(columnId) => void
default —
A spur, and any spurs opened from it, was folded back (Escape or its close button).
active / defaultActive
string
default — / the last column
The active column id, controlled or initial. The active column always stays open.
onActiveChange
(columnId) => void
default —
Fires from the key, spine, chip, phrase or swipe that changed the active column.
columnWidth
number
default 280
The width older open columns hold, in px — the newest column takes the rest — and the width a column needs to stay open; columns that no longer fit narrow to spines, oldest first.
spineWidth
number
default 40
A spine's width in px.
spineStyle
"label" | "index" | "bar"
default "label"
Spines read their phrase set vertically, show a large number with a dot per turn, or a slim accent bar under the number.
accent
string
default "var(--accent-bright)"
Phrase marks, the carried chip, spines, the active column's edge, trail chips and Send — any CSS colour.
stackBelow
number
default 520
Below this container width (px) the columns become a swipeable stack with a trail of chips.
allowSelection
boolean
default true
Selecting words in an answer offers "Ask about this" above the selection.
maxPhrase
number
default 64
The longest selection, in characters, that can become a spur.
title
string
default "Fernworks onboarding"
The first column's heading and the region's name.
status / onRetry
"ready" | "loading" | "error" / () => void
default "ready"
Loading shows skeleton columns; error shows a message and Try again, which calls onRetry.
height
number
default 540
The surface's height in px; each column scrolls inside it.
disabled
boolean
default false
Read only: columns can be walked and read; nothing can be opened, folded or asked.
className
string
default —
Classes for the outer section.