shadcn.io is not affiliated with official shadcn/ui
Job Applications Kanban Block for React Aria
A four-column job search board of nine applications, each with a company lettermark and a next step worked out as a date word from a fixed date, where Offer needs an interview first.
Installation
Overview
Keep a job search in view with this application board for React with React Aria. A hairline frame with a plus mark on each corner holds four columns that share their lines (Applied, Phone screen, Interview and Offer) and nine applications. Each card has the company's lettermark, two typed letters in a tile so no logo is needed, the company and role, what the next step is and when, as a date word in an outline Badge ("Tomorrow", "In 5 days", "2 days overdue") beside the calendar date in a time element. Push a week Button moves the step a week on. The words are worked out from one fixed date, so they never depend on the clock. An application can't reach Offer without passing Interview, and the refusal says so. Every column head counts its applications and names the earliest next step, and the sentence under the heading counts what falls this week and what is overdue. A card moves by dragging its grip, from the keyboard, or from its Dropdown Menu under "Move to"; a polite status line in the foot reports each change and Reset puts the board back. The frame is ruled by Guides. For job searches, hiring pipelines and any process that waits on a date.
FAQ
How are the date words worked out?
From the constant AS_OF, a fixed date, not the clock: daysTo counts whole days from it to a card's next date and dayWord turns the count into "Today", "Tomorrow", "In 5 days" or "2 days overdue". Because nothing reads the current time, the server and the browser print the same words. To use today's date, set AS_OF from your own data when you render.
How does the Offer rule work, and how do I change it?
The function refusalOf gets the cards, the application, the column it comes from and the column it is going to, and returns a reason or an empty string. Here it refuses Offer from anywhere but Interview. The drop, the keyboard steps and the menu all ask it. Replace the body to suit your own pipeline, for example to require a reference check.
Can I use real company logos?
The lettermark is two typed letters, never derived from the name, so two companies never share a tile by accident. To use a logo, replace the tile's text with an image you have the rights to use. The company names here are made up.
How do I move a card without a mouse?
Tab to the grip at the start of a card, named "Move" with the card's title. Press Space or Enter to pick it up, then ArrowUp and ArrowDown to change its place, ArrowLeft and ArrowRight to go to the neighbouring column (the arrows swap in right-to-left languages), Home and End for the first and last place, Space or Enter to drop it and Escape to put it back. Every step is announced in the status line, with the column and the position.
Why is there a menu as well as the grip?
Dragging needs a held pointer and a path, which not everyone has, so each card also has a "More actions" menu with a "Move to" choice for every column and the current one ticked. Choosing one moves the card, puts focus on the card in its new place and says so in the status line. React Aria's menu is a group of selectable items, so the column is chosen by selection rather than by a radio item.
What stays in the demo, and how do I save the moves?
Everything: the moves live in the component's state, nothing is sent anywhere, and a reload or Reset brings back the starting board. To save for real, call your API from put for every finished move and from act when a step is pushed, and use the dates your API returns. The names and figures are made up.
How does it work on a phone?
The board is a sideways scroll region with the next column showing, and each column scrolls up and down inside the board's fixed height, so the page never jumps. Touch drags from the grip only, so the rest of a card still scrolls the board; the menu is the other way to move a card. The status line is still read out to screen readers.