Ticket router
ProA support ticket router where messages from Gmail, Intercom, Slack and Zendesk come in one at a time. An AI classifier labels each one with intent, sentiment and confidence, and the ticket moves into a team lane with an assignee. Low confidence tickets wait in a review lane, and one click there routes them to the suggested team.
- Receipt is missing our address
Andre92% - Update the card on file
Sofia96%
- API returns 429 since 14:00 UTC
Daniel93% - SAML login loops on Safari 19
Olivia95%
- Dark mode for the mobile app
Jordan90%
- Showing how an AI classifier triages inbound support messages into team queues.
- A live triage widget in a helpdesk or ops dashboard, with a human review lane for low confidence.
- Landing page or onboarding demos of AI routing for support products.
- A full ticket inbox with search and bulk actions; use a table or list layout.
- A single tool step in a chat transcript; use tool-call.
- Generic multi step agent progress; use agent-status or agent-plan.
Installation
Pro source and install commands unlock with a Pro plan.
import { TicketRouter } from "@/components/arc/ticket-router/ticket-router"; export function SupportInbox({ tickets }) { return ( <TicketRouter tickets={tickets} reviewThreshold={0.75} classify={async (ticket, { signal }) => { const res = await fetch("/api/classify", { method: "POST", body: JSON.stringify(ticket), signal }); return res.json(); // { intent, sentiment, confidence } }} onRoute={ticket => assignInHelpdesk(ticket.id, ticket.lane, ticket.assignee)} /> );}TicketRouter
A support ticket router card. Messages from Gmail, Intercom, Slack and Zendesk arrive one at a time, an AI classifier labels intent, sentiment and confidence, and the ticket lands in a team lane with a round robin assignee. Low confidence tickets go to the review lane, where a click confirms the suggested lane. With no props it plays a simulated inbox.
ticketsTicketMessage[]ticketRouterSamplesIncoming messages, processed in order. Each has id, channel (email, intercom, slack, zendesk), customer, company, subject, preview and an optional receivedAt label.lanesTicketLane[]Billing, Engineering, Success, Needs reviewTeam lanes left to right: id, label, assignees for round robin, count for tickets routed earlier, and review: true on the lane that collects low confidence tickets.initialRoutedRoutedTicket[]samples when tickets is unsetTickets already in the lanes on first render, newest first.classify(ticket, { signal }) => Promise<TicketClassification>–Your classifier. Resolve { intent, sentiment, confidence }; throw to show the error state with Retry and Send to review. The signal aborts on pause, off screen and unmount. Without it a simulated classifier reads each ticket's sample.route(ticket, classification) => stringbilling and refund to billing, bug to engineering, feature to successPicks the lane id for a confident classification.reviewThresholdnumber0.7Confidence below this sends the ticket to the review lane with the picked lane as a suggestion.loopbooleantrue for samples, false for your ticketsStarts over when the queue runs out. Without it the card shows All caught up, and resumes when you append tickets.pausedboolean–Controls the flow. Pair with onPausedChange.defaultPausedbooleanfalseStarts paused when uncontrolled.onPausedChange(paused: boolean) => void–Called by the Pause and Resume button.onRoute(ticket: RoutedTicket) => void–Called when a ticket lands in a lane, with its classification, lane, assignee and suggested lane.onReview(ticket: RoutedTicket, lane: string) => void–Called when someone confirms a review ticket's suggested lane.onError(ticket: TicketMessage, error: unknown) => void–Called when the classifier throws.maxVisiblenumber3Rows shown per lane. Narrow containers show at most 2.speednumber1Playback speed multiplier for the simulated flow.titlestring"Ticket routing"Card title.modelstring"Claude Haiku 5.5"Classifier model name in the header and the classifying label.modelMarkReactNodeClaude markMark shown before the title.classNamestring–Extra class on the root section.- Tab
- Moves between Pause, the error actions and review tickets.
- EnterorSpace
- Pauses or resumes, retries a failed classification, or confirms a review ticket's suggested lane.
- The card is a section labelled by its title. Each lane is a list labelled with its name and ticket count.
- A polite live region announces each routing ("routed to Billing, assigned to Andre Williams"), failures, pauses and review confirmations, and says when the run is simulated and nothing was sent.
- Intent, sentiment and review status always pair an icon with a text label; confidence reads as a percentage, never color alone.
- Review tickets are real buttons with a label naming the subject, confidence and target lane.
- About two seconds per ticket: arrive 220ms, classify, labels fade in with a 50ms stagger, then a pulse draws along the connector to the target lane in 240ms and the row lands.
- Rows enter and leave by animating their measured height with a bounce free spring (visualDuration .24). Counters roll in reserved tabular width.
- Ticket swaps are a single crossfade: out in 100ms, in over 160ms with a small rise. No blur, no per letter motion.
- Reduced motion keeps every end state and the landing highlight, and drops travel, rises and the connector draw. The flow pauses off screen.
- Fills its container up to 840px. Four lanes sit in a row with a connector above 600px of content width; below that they form a 2 by 2 grid with two rows each.
- Below 600px the classifier labels stack above the route target; below 400px the confidence meter and model name hide, keeping the percentage.
- Every text line truncates with an ellipsis, so long subjects and names never change the card height.
- One timer or one classifier call runs at a time; both cancel on pause, off screen (IntersectionObserver) and unmount.
- Routed history is capped at 80 tickets and each lane renders only its visible rows.
- Marks are inline SVG with no network requests; avatars use the shared image component.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for support triage, helpdesk automation and AI routing previews. Wire classify to your model call and onRoute to your helpdesk API.
- Lane ids returned by route must match lanes; an unknown id falls back to the first non review lane.
- Pass loop={false} with your own tickets to get the empty and All caught up states. Append to tickets to keep the flow going.
- Keep it inside a content column (360 to 880px). Below 600px the lanes fold into a 2 by 2 grid and the connector hides.
The full library index for assistants is at /llms.txt.