KQ-1329 · HELP/PANEL
Help Panel
A support panel that grows out of a corner launcher: one surface carried from the launcher's circle to the panel's box on glide, shrinking back into it on the exit ease, while the launcher's mark turns into a cross on snap. Inside, views move by direction (a push arrives from 16px right on snap, Back reverses): search with articles suggested for the page before you type and live results with the matched words marked, an article with a helpful vote, a contact form, and a handoff to a live chat where the agent joins, a typing indicator waves and replies arrive on snap, or to a ticket. The search is a combobox over a listbox (Down and Up move, Enter opens), the dialog keeps Tab inside, and Escape steps back a view, clears the search, then closes and returns focus to the launcher.
Today
5 routes · 49 stops
- North loop14 stopsOn time
- Harbour run9 stopsLate
- Market district11 stopsOn time
- Depot transfer3 stopsDone
- Riverside12 stopsOn time
Help
Hi Dana,
How can we help?
help open · 3 suggested for routes
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/help-panel
Props
- articles
- HelpArticle[]
- default defaultHelpArticles
- The help centre: id, title, summary, body paragraphs, tags, reading time, views and when it changed.
- context
- string
- default "routes"
- The page the visitor is on, matched against articles' tags for suggestions.
- contextLabel
- string
- default "Routes"
- How that page is named in "Suggested for …".
- open / defaultOpen
- boolean
- default — / false
- The panel is open.
- onOpenChange
- (open: boolean) => void
- default —
- Fires from the launcher, the close button or Escape.
- corner
- "bottom-right" | "bottom-left" | "top-right"
- default "bottom-right"
- The corner the launcher sits in; the panel grows out of it.
- suggest
- "page" | "popular" | "off"
- default "page"
- What waits under the search before anything is typed: articles for this page, the most read, or nothing.
- handoff
- "chat" | "ticket" | "instant"
- default "chat"
- Where contacting support leads: a live chat after the form, a ticket after the form, or straight to the chat.
- greeting
- string
- default "How can we help?"
- The line under the visitor's name on the home view.
- user
- HelpUser
- default defaultHelpUser
- Who is asking: names the greeting and fills the form's email.
- agent
- HelpAgent
- default defaultHelpAgent
- Who answers the chat: name, role, initials and usual reply time.
- replies
- string[]
- default defaultHelpReplies
- Uncontrolled chat: what the agent says to each of your messages, in order; {name} and {topic} are filled in.
- messages
- HelpMessage[]
- default —
- Controlled chat: the conversation. When given, the panel shows it and scripts nothing.
- agentTyping
- boolean
- default —
- Controlled chat: the agent is typing.
- onSend
- (text: string) => void
- default —
- You sent a chat message.
- onArticleOpen
- (article: HelpArticle) => void
- default —
- An article was opened from a list.
- onHelpful
- (articleId: string, helpful: boolean) => void
- default —
- Yes or No on "Was this helpful?".
- onContactSubmit
- (form: HelpContactForm) => void | Promise<void>
- default —
- Sends the contact form (topic, message, email). A promise holds Send pending; a rejection's message is shown.
- onHandoff
- (kind: "chat" | "ticket") => void
- default —
- Support took over: a chat started or a ticket was opened.
- onViewChange
- (view: HelpView) => void
- default —
- The view on screen changed: home, article, contact, chat or ticket.
- topics
- string[]
- default ["Routes", "Billing", "Account", "Something else"]
- The contact form's topic chips.
- now
- Date | number
- default —
- The clock chat messages are stamped with; without it, the time each one arrives.
- status
- "ready" | "loading" | "error"
- default "ready"
- Loading draws placeholder articles; error offers Retry.
- onRetry
- () => void
- default —
- The Retry button of the error state.
- fixed
- boolean
- default false
- Sit in a corner of the viewport instead of the page passed as children.
- children
- React.ReactNode
- default —
- The page the launcher sits on.
- label
- string
- default "Help"
- The panel's accessible name and kicker.
- sound
- boolean
- default false
- A swish as you open, close and move between views; a pop when you send, vote or send the form. The agent makes no sound.
- disabled
- boolean
- default false
- Shows the launcher but takes no input.
- className
- string
- default —
- Classes for the root, which wraps the page.
| Prop | Type | Default | Description |
|---|---|---|---|
| articles | HelpArticle[] | defaultHelpArticles | The help centre: id, title, summary, body paragraphs, tags, reading time, views and when it changed. |
| context | string | "routes" | The page the visitor is on, matched against articles' tags for suggestions. |
| contextLabel | string | "Routes" | How that page is named in "Suggested for …". |
| open / defaultOpen | boolean | — / false | The panel is open. |
| onOpenChange | (open: boolean) => void | — | Fires from the launcher, the close button or Escape. |
| corner | "bottom-right" | "bottom-left" | "top-right" | "bottom-right" | The corner the launcher sits in; the panel grows out of it. |
| suggest | "page" | "popular" | "off" | "page" | What waits under the search before anything is typed: articles for this page, the most read, or nothing. |
| handoff | "chat" | "ticket" | "instant" | "chat" | Where contacting support leads: a live chat after the form, a ticket after the form, or straight to the chat. |
| greeting | string | "How can we help?" | The line under the visitor's name on the home view. |
| user | HelpUser | defaultHelpUser | Who is asking: names the greeting and fills the form's email. |
| agent | HelpAgent | defaultHelpAgent | Who answers the chat: name, role, initials and usual reply time. |
| replies | string[] | defaultHelpReplies | Uncontrolled chat: what the agent says to each of your messages, in order; {name} and {topic} are filled in. |
| messages | HelpMessage[] | — | Controlled chat: the conversation. When given, the panel shows it and scripts nothing. |
| agentTyping | boolean | — | Controlled chat: the agent is typing. |
| onSend | (text: string) => void | — | You sent a chat message. |
| onArticleOpen | (article: HelpArticle) => void | — | An article was opened from a list. |
| onHelpful | (articleId: string, helpful: boolean) => void | — | Yes or No on "Was this helpful?". |
| onContactSubmit | (form: HelpContactForm) => void | Promise<void> | — | Sends the contact form (topic, message, email). A promise holds Send pending; a rejection's message is shown. |
| onHandoff | (kind: "chat" | "ticket") => void | — | Support took over: a chat started or a ticket was opened. |
| onViewChange | (view: HelpView) => void | — | The view on screen changed: home, article, contact, chat or ticket. |
| topics | string[] | ["Routes", "Billing", "Account", "Something else"] | The contact form's topic chips. |
| now | Date | number | — | The clock chat messages are stamped with; without it, the time each one arrives. |
| status | "ready" | "loading" | "error" | "ready" | Loading draws placeholder articles; error offers Retry. |
| onRetry | () => void | — | The Retry button of the error state. |
| fixed | boolean | false | Sit in a corner of the viewport instead of the page passed as children. |
| children | React.ReactNode | — | The page the launcher sits on. |
| label | string | "Help" | The panel's accessible name and kicker. |
| sound | boolean | false | A swish as you open, close and move between views; a pop when you send, vote or send the form. The agent makes no sound. |
| disabled | boolean | false | Shows the launcher but takes no input. |
| className | string | — | Classes for the root, which wraps the page. |