Skip to content
txbrendan/ui

Projects Page

beta

A whole projects page for an app: the left rail beside one set of projects shown as a board, a list, or a timeline. On narrow screens the rail moves into a menu.

Built from Rail, Sheet, Button, and Tooltip.

Preview

Workspace

Projects

10 projects across 4 stages

Wireframes
Design

Rough layouts for the new settings pages.

x
0/6 tasks0%
2comments4filesDueNov 13
Push alerts
MobileUrgent

Alerts for replies and due dates on phones.

x
0/5 tasks0%
4commentsDueNov 9
Team permissions
Platform

Roles for owners, editors, and viewers.

x
2/12 tasks17%
2filesDueDec 4
Payments page
WebUrgent

One page for cards, bank details, and receipts.

x
9/20 tasks45%
12comments6filesDueNov 6
Onboarding emails
Marketing

A short series for the first week after sign up.

x
4/7 tasks57%
3comments1filesDueNov 5
Mobile app
Mobile

The first release for phones, with sign in and lists.

x
14/40 tasks35%
21comments9filesDueDec 11
Help center
Web

Search and short guides for the top questions.

x
18/20 tasks90%
7comments3filesDueOct 31
Brand refresh
Design

New type, colors, and icons across the app.

x
11/12 tasks92%
9comments14filesDueNov 3
Billing update
Web

Plans and seats on one page.

x
10/10 tasks100%
6comments2filesDueOct 21
Reports hub
Platform

Every report in one place, with exports.

x
15/15 tasks100%
3comments5filesDueOct 24

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-page

Use it for

  • The projects screen of an app. Render it as the whole page, from your app's page file.
  • Pass the rail's places in `rail` and the projects in `projectViews`. Each takes the props of its own part.
  • Mark the place you're in with the rail's `active` or `defaultActive`. The rail beside the page and the one in the menu stay in step.
  • Render one Toaster on the page, so moving or removing a project can offer Undo.
  • Set `embedded` when you show the page inside another page, like a gallery, so it has no second main.

Avoid it for

  • The rail's `onSearch` here. The rail draws twice, beside the page and in the menu, so its shortcut would listen twice. Put search in a Command Menu instead.
  • A hero, a tagline, or a feature grid on top. An app screen leads with the work.

Props

  • rail

    Required. The Rail's props: the app's name, the places, and Settings. Below 40rem the rail moves into a menu, and its header sits beside the menu button.

    RailProps

  • projectViews

    Required. The Project Views block's props: the projects, the stages, today, and the view to start on.

    ProjectViewsProps

  • menuLabel

    Names the menu button and the menu on narrow screens.

    string · default "Menu"

  • embedded

    Renders the content in a div, not a main, for a preview inside another page.

    boolean · default false

  • className

    Extra classes on the page. Later classes win.

    string

Accessibility

  • The content sits in one main, unless embedded is set.
  • On narrow screens the menu button has its label as its name and its tooltip, and the menu opens as a dialog named by the same label. Choosing a place closes it.
  • The rail and the projects keep their own keyboard and screen reader behavior.

Examples

Projects beside the app's rail

<ProjectsPage
  rail={{
    header: <span className="px-2 font-(--type-weight-strong)">Workspace</span>,
    groups: [{ items: [{ id: "home", label: "Overview", icon: "house" }, { id: "projects", label: "Projects", icon: "file-text" }] }],
    defaultActive: "projects",
    footer: { id: "settings", label: "Settings", icon: "settings" },
  }}
  projectViews={{
    today: "2026-10-30",
    defaultProjects: [
      { id: "help", name: "Help center", stage: "review", start: "2026-10-12", due: "2026-10-31" },
      { id: "payments", name: "Payments page", stage: "doing", start: "2026-10-19", due: "2026-11-06" },
    ],
  }}
/>

A narrow-screen menu with its own name

<ProjectsPage
  menuLabel="Places"
  rail={{
    groups: [{ items: [{ id: "home", label: "Overview", icon: "house" }, { id: "projects", label: "Projects", icon: "file-text" }] }],
    defaultActive: "projects",
  }}
  projectViews={{ today: "2026-10-30" }}
/>