Dashboard & Data Table Design That Survives Real Data

    1

    Dashboards and tables that hold up at 4,000 messy rows: density, columns, filters, bulk actions, and every state.

    $9

    Secure checkout via Stripe

    30-day refund guarantee

    Converts to your local currency at checkout

    0 installsSecurity scanned

    Works with the AI tools you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIGitHub CopilotGitHub CopilotGemini CLIGemini CLI+20 more

    Dashboard & Data Table Design That Survives Real Data

    Example session with this skill installed

    Design the refunds queue for our payments admin tool. Support agents live in this all day — they work through pending refund requests and approve or reject them.

    Data shape: ~2,000 pending at any time, 40k total. Columns available: refund id, customer email (some are 50+ chars), order id, amount, currency, reason (free text, often empty), status (pending / approved / rejected / failed), requested date, assigned agent (nullable — about 60% unassigned).

    Agents need to filter by status and assignee, search by email or order id, and approve/reject in bulk.

    • Read your context and instructions
    • Compiled the dashboard & data
    • Generated the UI component

    Refunds Queue

    Answers the question: what do I work on next, and can I clear a batch of it at once?
    Users: support agents, all day, every day. Power users — density and keyboard matter more than polish.
    Data reality: 2k pending / 40k total · email up to 50+ chars · reason often empty · assigned_agent null ~60% · status cardinality 4
    Next action: approve or reject, individually or in bulk.

    This is an operational worklist, not an analytics dashboard. That decides almost everything below: density over beauty, the queue is the page, and metrics at the top are navigation rather than decoration.


    Layout

    ┌──────────────────────────────────────────────────────┐
    │ Refunds                              [Export] [⚙]    │
    ├──────────────────────────────────────────────────────┤
    │ [Unassigned 1,204] [Mine 87] [Pending 2,041] [Failed 12]│  ← filter tabs, not stat tiles
    ├──────────────────────────────────────────────────────┤
    │ 🔍 search      Status ▾  Assignee ▾  Date ▾   ⚙ 25▾  │
    │ Status: Pending ×   Assignee: Unassigned ×  Clear all │
    ├──────────────────────────────────────────────────────┤
    │ ☐ │ Requested │ Customer │ Order │ Amount │ Status │⋯│
    │ ...                                                   │
    ├──────────────────────────────────────────────────────┤
    │ Showing 1–50 of 1,204            ‹ 1 2 3 … 25 ›      │
    └──────────────────────────────────────────────────────┘
    

    Focal point: the table. It gets everything below the filter bar.

    The counts are tabs, not tiles. An agent doesn't want to know there are 1,204 unassigned — they want to work on them. Making the count clickable collapses "read a number" and "apply a filter" into one action, and removes a whole row of decorative tiles from a screen where vertical space is the scarcest resource.

    Failed gets a red dot when > 0. It's the only one that's an alarm rather than a queue.


    Columns

    7 visible. Everything else behind the column picker.

    #ColumnTypeAlignWidthSortableTruncationNotes
    Selectcheckbox44px fixedHeader selects page
    1Requesteddateleft110px fixeddefault descRelative < 7d ("2d ago"), absolute after; exact on hover
    2Customeremailleftflex, max 260pxMiddle-ellipsis + tooltipThe scanning column
    3Orderidleft120px fixedMonospace, links to order
    4Amountcurrencyright110px fixedtabular-nums, 2dp, symbol per row (mixed currency)
    5Statusenumleft110px fixedBadge + label
    6Assigneeuserleft140px fixedAvatar + first name when null, not "Unassigned"
    7Actionsright96px fixedApprove / Reject inline

    Hidden by default: Refund ID, Reason, Currency code, Payment method, Order total, Customer since

    Middle-ellipsis on email, not end-ellipsis. jonathan.mcallister@… tells you nothing; jonathan.m…@acmecorp.com keeps the domain, which is what agents actually scan for. This is the single highest-value detail in the spec for this particular table.

    Mixed currency means no column-level unit. Symbol goes in the cell (€42.00), and sorting by Amount must sort by a normalised value or it's nonsense — flag to engineering.

    reason stays hidden. Free text that's usually empty is the worst possible default column: it's mostly whitespace and occasionally 400 characters. It belongs in the row expansion.

    Default sort: Requested, descending. Tiebreak: refund id, ascending.


    Density

    Default: compact, 36px rows. Agents live here; 50 rows on screen beats 25 comfortable ones. Offer the density control in the toolbar and persist per user.

    DensityRow height
    Compact (default)36px
    Default44px
    Comfortable56px

    Cell padding-x 12px, first/last 16px. 1px bottom border, no zebra striping — 7 columns doesn't need it.


    Filters & search

    ControlTypeBehaviour
    Searchtext, debounce 300msMatches email and order id. Placeholder: Search email or order ID
    Statusmulti-selectDefault: Pending only
    AssigneeselectMe · Unassigned · any agent · Anyone
    Datepreset + custom7d / 30d / all. Default: all
    • Active filters as removable chips, always visible. Clear all at 2+.

    Filter state in the URL. Agents paste these links to each other constantly — "can you take this batch". Non-negotiable in a support tool.

    • Count: Showing 1–50 of 1,204
    • Spinner goes in the search field, never over the table.

    Pagination

    Pagination, not infinite scroll. Agents process systematically and need to know where they are; infinite scroll also breaks the bulk-action bar. Page sizes 25 / 50 / 100, default 50. First/last jumps.


    Selection & bulk actions

    • Header checkbox selects the page.
    • Full page selected + more matching → All 50 on this page selected. [Select all 1,204 matching]
    • Bulk bar pins to the bottom on selection: 3 selected · Approve · Reject · Assign to me · Clear

    Confirmation names the count and the money: Approve 1,204 refunds totalling €48,210.55? — the amount is the number that stops a mistake.

    • Bulk reject requires a reason (select + optional note). Approve doesn't.
    • Progress past 2s: Approving 340 of 1,204…
    • Partial failure: 1,198 approved, 6 failed. [View failures] — never report "Done" when some failed.
    • Selection survives sort. Clears on filter change, with a toast saying so.

    Row actions

    Approve and Reject as inline buttons — they're 95% of the work, so they don't go in an overflow menu. Overflow (⋯) holds View order · Assign · Copy refund ID · View customer.

    Row click expands inline (reason, payment method, customer history), rather than navigating away. Agents lose their place otherwise.


    States

    StateDesign
    Initial load8 skeleton rows at 36px, real column widths
    RefetchRows stay at 60% opacity, 2px progress bar on the table top edge — never blank
    Slow > 5sStill loading — searching 40,000 refunds + [Cancel]
    Empty — first usen/a (queue is never empty on first use)
    Empty — filteredNo refunds match / Status: Pending · Assignee: me / [Clear filters]
    Empty — all clearQueue clear / Nothing pending. New requests appear here.
    Error — wholeCouldn't load refunds / [Try again] — filter bar and chrome preserved
    Error — partialCounts fail independently of the table; each retries alone
    Error — rowInline on the row: ⚠ Approval failed — card issuer declined · [Retry], row stays
    StaleUpdated 2 min ago · [Refresh] — poll every 60s, never auto-refresh mid-selection
    CappedNot applicable — pagination handles 40k

    The "all clear" empty state matters more than it looks. It's the only moment of the day the agent gets to feel finished. Acknowledge it.


    Responsive

    Agents are on desktop, so optimise there — but support tablet for on-call.

    WidthBehaviour
    < 768pxCard per row: customer + amount on line 1, status + date line 2, actions full-width. Bulk actions disabled.
    768–1280pxPriority columns (Requested, Customer, Amount, Status, Actions), rest behind row expansion
    > 1280pxFull 7 columns

    Keyboard

    Daily-use tool, so this earns its place:

    KeyAction
    /Focus search
    j / kNext / previous row
    xToggle selection
    aApprove focused row
    rReject focused row (opens reason)
    EnterExpand row
    EscClear selection / collapse
    ?Shortcut help

    a and r need a 3-second undo toast, since they're single-keypress and destructive-ish.


    Performance

    • Server-side sort, filter and paginate — 40k rows, non-negotiable.
    • No virtualisation needed at 50 rows/page.
    • Poll 60s, paused while rows are selected or a row is expanded.
    • Target p95 < 400ms for the filtered query; the search index needs to cover email and order id.

    Accessibility

    • Real <table>, <th scope="col">, <caption class="sr-only">Refund requests</caption>
    • aria-sort on the sorted header; sort control is a <button> inside the <th>
    • Sticky header with an explicit background ✅
    • Showing 1–50 of 1,204 in an aria-live="polite" region ✅
    • Approve/Reject reachable by keyboard, never hover-only ✅
    • Status badge = colour + label (failed vs rejected must not rely on red vs grey) ✅
    • Bulk bar announced on appearance; count updates announced politely ✅

    Open decisions

    • DECISION NEEDED: does approving assign the refund to the acting agent automatically? Recommend

    yes — it's an audit trail agents shouldn't have to maintain by hand.

    • DECISION NEEDED: should failed refunds sit in this queue or their own? Recommend

    own view — they need investigation, not approval, and they pollute the working count.

    dashboard-data-table-design-that-survive.tsx

    TSX · React component

    Generated

    Example file from a real run - the skill writes it into your workspace.

    Connects securely to your tools. The creator never sees your data.

    What you get

    Define column alignment and numeric formatting for financial data grids.Spec out bulk action workflows and selection states for internal tools.Plan skeleton loaders and error states for high-latency data queries.Optimize dashboard hierarchy for high-density information layouts.

    About this skill

    The problem

    Dashboards look fine with six tidy rows and fall apart with four thousand messy ones. The email that's 60 characters long pushes the actions column off screen. Every filter change blanks the table. Nobody designed the empty state, the loading state, or what happens when one query times out — so the whole page fails.

    What it does

    • Designs the layout from the question the screen answers, not from a 12-column grid: context bar, headline metrics with real comparisons, one focal view, supporting detail.
    • Specifies the table properly — column order and alignment (numbers right, always), how many are visible by default, fixed vs flex widths, truncation per column, sorting with a sensible default and a tiebreak.
    • Covers filters and search as one system: chips for active filters, state in the URL, result counts, debounce timing, and when pagination beats infinite scroll.
    • Enumerates the nine states that get skipped — initial load, refetch, slow query, three kinds of empty, whole-table error, partial failure, row-level error — with the copy for each.
    • Handles responsive honestly: a table doesn't become a smaller table. Card per row, priority columns, or frozen-column scroll — with the tradeoffs.
    • Includes real measurements: row heights by density, cell padding, sticky header CSS, tabular-nums, badge sizing, breakpoint behaviour.

    Why this beats prompting it yourself

    It designs against your actual data shape — row counts, longest values, nullable fields, status cardinality — rather than against the six perfect rows in the example. And it forces the states and the bulk-selection escalation ("select all 1,247 matching") that cause real incidents when they're left unspecified.

    Use cases

    • Building an admin panel or internal tool
    • A SaaS dashboard that needs to be acted on, not just read
    • Fixing a table that works in dev and breaks on production data
    • Speccing a CRUD interface before writing it

    Known limitations

    Chart selection and palette are out of scope — pair it with a data-viz skill. Assumes a web interface; doesn't cover native mobile table patterns.

    How to install

    Works the same in every agent - Claude, Cursor, Codex, Copilot and 20+ more.

    ~30 seconds
    1. 1

      Download the ZIP

      Free skills download straight away. Paid skills unlock right after purchase.

    2. 2

      Unzip into your skills folder

      Every agent reads skills from one folder on your machine. Drop the unzipped folder in there.

    3. 3

      Ask your agent to use it

      Restart the agent if it was already running. It picks the skill up automatically - no config needed.

    Skills folder by agent

    Click the path to copy it. Create the folder if it does not exist yet.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill passes our trust checks below.

    Security scanned

    Passed our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    30-day refund

    Not a fit? Get your money back

    Trust & safety

    Security scanned

    Verified clean 7 days ago

    • Passed all security checks, Safe to install

    Listed7 days ago

    What's inside

    Frequently Asked Questions