Table

A table lists records that share the same fields: members, keys, invites, audit events. Under 640px each row stacks into a card with its column header beside each value.

Previewapps/web/components/ui/KbTable.tsx

Columns, numbers and row actions

Numbers are right-aligned with tabular figures. Row actions sit in the last column.

Team members
NameRoleOpen requestsActions
Ana RuizOwner12
Dev PatelAgent4
Show code
<KbTable caption="Team members" rows={rows} rowKey={(r) => r.id} columns={columns}
  rowActions={(r) => <KbButton variant="ghost" size="sm" aria-label={`Remove ${r.name}`}>Remove</KbButton>} />

Identity cell and row open

The first column can hold an avatar, a name and a quiet line. With rowHref or onRowOpen the first cell becomes the real link or button and its hit area covers the row.

Contacts
NameOpen requests
Ana RuizOwner12
Dev PatelAgent4
Show code
<KbTable caption="Contacts" rows={rows} rowKey={(r) => r.id} rowHref={(r) => `/admin/contacts/${r.id}`} rowOpenLabel={(r) => `Open ${r.name}`}
  columns={[{ key: "who", header: "Name", cell: (r) => <KbIdentityCell name={r.name} sub={r.role} /> }]} />

Empty

No pending invites. Invite a teammate above.
Show code
<KbTable caption="Pending invites" rows={[]} rowKey={(r) => r.id} columns={columns}
  empty="No pending invites. Invite a teammate above." />