Skip to content
txbrendan/ui

Projects

beta

A projects page with board, list, and timeline layouts that share one shell per project.

Built from Badge, Card, Progress, Ring Progress, Search Field, Select, Skeleton, Tooltip, View morph, and View switch.

Preview

Projects

14 projects

14 projects

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

  • To do4
  • In progress3
  • In review2
  • Done5

List

Projects

14 projects

14 projects

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

ProjectPriorityProgressRolesDue
To do4
High
x
Lead, BuildNov 18
Medium
x
WriteNov 21
Low
x
Write, ReviewDec 2
Low
x
DesignDec 2
In progress3
Urgent
x
Lead, Build, ReviewNov 3
High
x
Lead, BuildNov 12
Medium
x
ReviewNov 20
In review2
High
x
Design, LeadOct 31
Medium
x
BuildNov 5
Done5
Low
x
Write, ReviewOct 22
Medium
x
BuildOct 15
Medium
x
Lead, BuildOct 24
Low
x
WriteOct 17
High
x
Review, DesignOct 27

Timeline

Projects

14 projects

14 projects

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

Oct 13Nov 1Dec 1Example · Oct 27

The date line marks a fixed example, Oct 27, 2026.

To do4
  • 0% · 0/14Nov 18
  • 20% · 2/10Nov 21
  • 0% · 0/8Dec 2
  • 0% · 0/8Dec 2
In progress3
  • 45% · 9/20Nov 3
  • 75% · 18/24Nov 12
  • 60% · 12/20Nov 20
In review2
  • 88% · 22/25Oct 31
  • 83% · 10/12Nov 5
Done5
  • 100% · 16/16Oct 22
  • 100% · 18/18Oct 15
  • 100% · 12/12Oct 24
  • 100% · 9/9Oct 17
  • 100% · 14/14Oct 27

Loading board

Projects

Loading projects

 

Loading list

Projects

Loading projects

 

Loading timeline

Projects

Loading projects

 

Empty page

Projects

No projects yet.

 

No projects yet.

Empty group

Projects

12 projects

12 projects

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

  • To do4
  • In progress3
  • In review0

    Nothing in In review.

  • Done5

Nothing matches

Projects

No projects match.

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

No projects match.

Overdue

Projects

14 projects

14 projects

Example records. Roles stand in for people, and Nov 6, 2026 is a fixed date.

 

ProjectPriorityProgressRolesDue
To do4
High
x
Lead, BuildNov 18
Medium
x
WriteNov 21
Low
x
Write, ReviewDec 2
Low
x
DesignDec 2
In progress3
Urgent
x
Lead, Build, ReviewOverdue Nov 3
High
x
Lead, BuildNov 12
Medium
x
ReviewNov 20
In review2
High
x
Design, LeadOverdue Oct 31
Medium
x
BuildOverdue Nov 5
Done5
Low
x
Write, ReviewOct 22
Medium
x
BuildOct 15
Medium
x
Lead, BuildOct 24
Low
x
WriteOct 17
High
x
Review, DesignOct 27

Filtered

Projects

4 of 14

4 of 14

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

  • To do1
  • In progress1
  • In review1
  • Done1

Could not load

Projects

Projects could not be loaded. Check the connection and try again.

 

Long names

Projects

1 project

1 project

 

  • To do0

    Nothing in To do.

  • In progress1
  • In review0

    Nothing in In review.

  • Done0

    Nothing in Done.

Projects

1 project

1 project

 

ProjectPriorityProgressRolesDue
To do0
Nothing in To do.
In progress1
Urgent
x
Lead, Write, ReviewDec 1
In review0
Nothing in In review.
Done0
Nothing in Done.

Zoom 400

Projects

1 project

1 project

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

ProjectPriorityProgressRolesDue
To do1
High
x
Lead, BuildNov 18
In progress0
Nothing in In progress.
In review0
Nothing in In review.
Done0
Nothing in Done.

Narrow board

Projects

14 projects

14 projects

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

  • To do4
  • In progress3
  • In review2
  • Done5

Narrow timeline

Projects

14 projects

14 projects

Example records. Roles stand in for people, and Oct 27, 2026 is a fixed date.

 

Oct 13Nov 1Dec 1Example · Oct 27

The date line marks a fixed example, Oct 27, 2026.

To do4
  • 0% · 0/14Nov 18
  • 20% · 2/10Nov 21
  • 0% · 0/8Dec 2
  • 0% · 0/8Dec 2
In progress3
  • 45% · 9/20Nov 3
  • 75% · 18/24Nov 12
  • 60% · 12/20Nov 20
In review2
  • 88% · 22/25Oct 31
  • 83% · 10/12Nov 5
Done5
  • 100% · 16/16Oct 22
  • 100% · 18/18Oct 15
  • 100% · 12/12Oct 24
  • 100% · 9/9Oct 17
  • 100% · 14/14Oct 27

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the template. It also adds every component it uses. Its own files go in your components folder, and they are yours to edit.

    npx shadcn@latest add @txbrendan/projects

Use it for

  • A page of projects someone switches between a board, a list, and a timeline.
  • Pass projects, and a today date, when the records are yours. The defaults are a worked example, and the page says so.
  • Set embedded when the page sits inside another page, so it does not add a second main.
  • Set loading while the records are on the way. The skeleton matches the layout. An empty projects array is the empty page. A search or priority that matches nothing says so, and a filter that matches some says how many of the total.
  • Set error to a sentence that says what to do next, when the records could not be loaded.

Avoid it for

  • A table you sort and page. The list is one of three layouts of the same shells, not a data table.
  • A second accent color. Orange is only the high pill. Red is only the date line. Timeline bars share one neutral fill.

Props

  • projects

    The records. Default is a worked example.

    Project[]

  • today

    The date the page treats as today, YYYY-MM-DD. Omit it and the page uses 2026-10-27 and says that date is a fixed example. A project due before the date, and not done, is overdue.

    string

  • loading

    Shows a skeleton in the current layout's shape instead of the records.

    boolean · default false

  • error

    Replaces the records with this message. Say what to do next.

    string

  • embedded

    Renders a div instead of a main, for a preview inside another page.

    boolean · default false

  • titleLevel

    Heading level of the title. Default h1, or h2 when embedded.

    "h1" | "h2"

  • defaultLayout

    The layout on first paint, when layout is not set.

    "board" | "list" | "timeline" · default "board"

  • layout

    The layout that is showing. Use with onLayoutChange.

    "board" | "list" | "timeline"

  • onLayoutChange

    Called with the layout that was just chosen.

    (layout: "board" | "list" | "timeline") => void

  • defaultQuery

    The search box on first paint.

    string · default ""

  • defaultPriority

    The priority filter on first paint.

    "all" | "urgent" | "high" | "medium" | "low" · default "all"

  • interactive

    When false, the project controls leave the tab order. The layout switch stays.

    boolean · default true

  • className

    Classes on the root, which holds the container query.

    string

  • Part. Project

    One project. id is stable across layouts. start and due are YYYY-MM-DD. roles are job names, such as Lead, not people.

    { id: string; name: string; client: string; summary: string; stage: "todo" | "progress" | "review" | "done"; priority: "urgent" | "high" | "medium" | "low"; done: number; total: number; start: string; due: string; roles: string[] }

Accessibility

  • The page is a main, unless embedded. The title is an h1, or an h2 when embedded, unless titleLevel says otherwise.
  • The layout control is a tab list. The morph is the tab panel, named by the active tab.
  • The board is a list of lists: one list named Board, and a list named for each stage. The list is a table. The timeline groups its rows, and each group is a list named for its stage.
  • Each project has one button, named with the project, the client, and the priority. The card, the row, and the timeline name are that button. The priority pill is named with its level. A tooltip carries the summary, the priority, the roles, and the task count. Enter or Space selects it. A layout change that drops focus puts it back on that button.
  • Set interactive to false to take those buttons out of the tab order. The layout switch stays in it.
  • A timeline bar's text equivalent is the name, the priority, the start, the due date, and the percent. The row shows that priority once, on the pill.
  • A status outside the busy region says when the page is loading, empty, or filtered to nothing.
  • The move follows the motion tokens. Motion off and reduced motion do not translate the shells.

Examples

The worked example

<Projects />

Inside another page

<Projects embedded interactive={false} titleLevel="h1" />