Design Library

Public role lookup - compact ledger

public-role-compact-ledger.tsx

componentskill: emil-design-eng + design-taste-frontendsearchpublic-recordscompliancedenseledger

Variants of public-role-lookup-2026-q3: public-role-evidence-workspace, public-role-guided-rail

Brief

The prompt that produced this. Re-run it to generate more in the same taste.

Aesthetic
institutional utility - sober, exact, trust-first, compact, evidence-led, accessible
Reference
FLAIR public-person role lookup, verified desktop and 390px screenshots
Intent
make public-role research efficient and auditable without turning the interface into an identity profile
Guardrails
always keep source and retrieval context beside every record, use native labels and controls, make public-record scope explicit, collapse cleanly at 375px
never resolve identity automatically, surface private contact data, use ornamental motion, imply that a public record is a current fact

Install

pnpm dlx shadcn@latest add http://localhost:3040/r/public-role-compact-ledger.json

Source

Meta block and library type import stripped - this is what pastes cleanly elsewhere.

'use client'

import { ExternalLink, Filter, Search } from 'lucide-react'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'

const records = [
  {
    role: 'Municipal advisory commission member',
    publisher: 'Sample municipality register',
    period: '2025-2027',
    status: 'Current in source',
  },
  {
    role: 'Association board representative',
    publisher: 'Public appointments bulletin',
    period: '2022-2024',
    status: 'Historical',
  },
]

export default function PublicRoleCompactLedger() {
  const [expanded, setExpanded] = useState(0)

  return (
    <main className="min-h-[100dvh] bg-white text-zinc-950 dark:bg-zinc-950 dark:text-zinc-100">
      <header className="border-zinc-300 border-b dark:border-zinc-800">
        <div className="mx-auto flex min-h-14 max-w-7xl items-center justify-between px-4 sm:px-6">
          <p className="font-semibold tracking-[-0.02em]">Public role ledger</p>
          <p className="text-xs text-zinc-600 dark:text-zinc-400">Official sources only</p>
        </div>
      </header>

      <div className="mx-auto max-w-7xl px-4 py-8 sm:px-6">
        <form
          className="grid gap-3 border-zinc-400 border bg-zinc-50 p-4 sm:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto] dark:border-zinc-700 dark:bg-zinc-900"
          onSubmit={(event) => event.preventDefault()}
        >
          <label htmlFor="ledger-family-name" className="grid min-w-0 gap-1.5 font-medium text-xs">
            Family name
            <Input
              id="ledger-family-name"
              defaultValue="Valcour"
              autoComplete="family-name"
              className="h-10 rounded-none border-zinc-400 bg-white shadow-none focus-visible:border-[#000091] focus-visible:ring-[#000091]/20 dark:border-zinc-700 dark:bg-zinc-950"
            />
          </label>
          <label htmlFor="ledger-given-name" className="grid min-w-0 gap-1.5 font-medium text-xs">
            Given name
            <Input
              id="ledger-given-name"
              defaultValue="NoƩmie"
              autoComplete="given-name"
              className="h-10 rounded-none border-zinc-400 bg-white shadow-none focus-visible:border-[#000091] focus-visible:ring-[#000091]/20 dark:border-zinc-700 dark:bg-zinc-950"
            />
          </label>
          <Button
            type="submit"
            className="h-10 self-end rounded-none bg-[#000091] px-5 text-white transition-[transform,background-color] duration-[160ms] ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-[#1212a8] active:scale-[0.97] motion-reduce:transform-none motion-reduce:transition-none"
          >
            <Search aria-hidden className="size-4" />
            Search
          </Button>
        </form>

        <div className="mt-6 flex flex-col gap-3 border-zinc-300 border-b pb-4 sm:flex-row sm:items-end sm:justify-between dark:border-zinc-800">
          <div>
            <h1 className="font-semibold text-2xl tracking-[-0.025em]">2 records to review</h1>
            <p className="mt-1 text-xs text-zinc-600 dark:text-zinc-400">
              Sample dataset. A record is not an identity match.
            </p>
          </div>
          <Button
            type="button"
            variant="outline"
            size="sm"
            className="w-fit rounded-none border-zinc-400 transition-[transform,background-color] duration-[160ms] ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.97] motion-reduce:transform-none motion-reduce:transition-none dark:border-zinc-700"
          >
            <Filter aria-hidden className="size-4" />
            Filter records
          </Button>
        </div>

        <section className="mt-2" aria-label="Public role records">
          {records.map((record, index) => {
            const isExpanded = expanded === index
            return (
              <article
                key={record.role}
                className="grid min-w-0 border-zinc-300 border-b py-5 dark:border-zinc-800 lg:grid-cols-[minmax(0,1.8fr)_minmax(10rem,1fr)_8rem_9rem]"
              >
                <button
                  type="button"
                  aria-expanded={isExpanded}
                  onClick={() => setExpanded(isExpanded ? -1 : index)}
                  className="min-w-0 text-left transition-[transform,color] duration-[160ms] ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.99] motion-reduce:transform-none motion-reduce:transition-none"
                >
                  <span className="block font-semibold text-sm leading-5">{record.role}</span>
                  <span className="mt-1 block text-xs leading-5 text-zinc-600 lg:hidden dark:text-zinc-400">
                    {record.publisher}
                  </span>
                </button>
                <p className="hidden min-w-0 break-words pr-4 text-xs leading-5 text-zinc-600 lg:block dark:text-zinc-400">
                  {record.publisher}
                </p>
                <p className="mt-2 font-mono text-xs tabular-nums lg:mt-0">{record.period}</p>
                <p
                  className={`mt-2 text-xs lg:mt-0 ${
                    record.status === 'Historical'
                      ? 'text-zinc-600 dark:text-zinc-400'
                      : 'font-medium text-[#000091] dark:text-blue-400'
                  }`}
                >
                  {record.status}
                </p>

                {isExpanded && (
                  <div className="mt-4 border-zinc-300 border-t pt-4 lg:col-span-4 dark:border-zinc-700">
                    <div className="grid gap-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-center">
                      <p className="max-w-2xl text-xs leading-5 text-zinc-600 dark:text-zinc-400">
                        Review the publisher, dates, and jurisdiction before associating this record
                        with a case subject.
                      </p>
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        className="w-fit rounded-none border-[#000091] text-[#000091] transition-[transform,background-color] duration-[160ms] ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-blue-50 active:scale-[0.97] motion-reduce:transform-none motion-reduce:transition-none dark:border-blue-400 dark:text-blue-300 dark:hover:bg-blue-950"
                      >
                        Open official source
                        <ExternalLink aria-hidden className="size-4" />
                      </Button>
                    </div>
                  </div>
                )}
              </article>
            )
          })}
        </section>

        <footer className="mt-6 grid gap-3 text-xs leading-5 text-zinc-600 dark:text-zinc-400 sm:grid-cols-2">
          <p>Query and source access are retained in the audit log.</p>
          <p className="sm:text-right">Private addresses and contact data are excluded.</p>
        </footer>
      </div>
    </main>
  )
}