webdevpuneet.com

Table Row Detail Panel — Master-Detail List with Instant Inspector (JS)

Table Row Detail Panel (Master-Detail) · Tables · Plain HTML, CSS & JS · Live preview

CategoryTables

Copy & paste

Source Code

<div class="rdp-wrap">
  <div class="rdp-list">
    <div class="rdp-bar"><h3>Inbox</h3></div>
    <table class="rdp-table" id="rdpTable">
      <thead><tr><th>From</th><th>Subject</th><th>Date</th></tr></thead>
      <tbody id="rdpBody"></tbody>
    </table>
  </div>
  <div class="rdp-detail" id="rdpDetail">
    <div class="rdp-empty" id="rdpEmpty">
      <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 4h16v16H4z"/><path d="M4 4l8 8 8-8"/></svg>
      <p>Select a row to see its details here.</p>
    </div>
    <div class="rdp-content" id="rdpContent" hidden></div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

True master-detail layout
A fixed-size list beside a panel that updates in place, not an expanding row.
Instant panel updates
Clicking any row immediately re-renders the detail panel from that row's data.
Single source of truth
Both the list highlight and panel content derive from one selectedId lookup.
Genuine empty state
A dedicated prompt appears before any row is selected, not a default-open first row.
Real read-state mutation
Opening a message clears its unread flag in the actual data, not just visually.
Compact list, rich detail
The list truncates to essentials; the panel shows full content only once selected.
Selection highlight
The open row stays visually marked with an accent bar and tint.
Data-driven & no library
Renders from a MESSAGES array of objects — zero dependencies.

About this UI Snippet

Table Row Detail Panel — A Master List with an Always-Visible Inspector

Screenshot of the Table Row Detail Panel (Master-Detail) snippet rendered live

An email client's message list and reading pane is a specific, well-understood pattern: a compact list on one side, and a detail panel that updates instantly as you click different rows on the other — never expanding inline, never navigating away. This snippet builds that master-detail layout for a table in plain HTML, CSS, and vanilla JavaScript, distinct from an accordion-style expandable row that pushes content into the row itself.

Master-detail, not expand-in-place

An expandable table grows the clicked row taller to reveal its detail inline, pushing every row below it down the page. This pattern does the opposite: the list stays a fixed, compact grid, and a *separate* panel beside it shows the selected row's extended information. Clicking a different row doesn't grow anything — it swaps the panel's content instantly, exactly like clicking between emails in an inbox never resizes the message list.

One click, one source of truth

showDetail(id) looks up the clicked message by id, sets it as selectedId, and rebuilds both the list (to show the selection highlight and clear the unread dot) and the detail panel's content from that single message object. Because both halves of the UI render from the same lookup, the highlighted row in the list and the content in the panel can never disagree about which item is "current."

A real empty state before any selection

Before anything is clicked, the detail panel shows a dedicated empty state — an icon and "Select a row to see its details here" — rather than either a blank panel or a default-selected first row. This matches how a reading pane actually behaves the first time you open a mail client: there's a genuine prompt, not an implicit selection the user didn't make.

Read-state side effect, like a real inbox

Opening a message clears its unread flag and removes its bold styling and dot indicator on the very next render — a small but realistic detail that shows the detail panel isn't just a display surface, it's wired to actually mutate the underlying data the way clicking into an email marks it read.

Compact list columns, expanded detail content

The list intentionally shows only three columns (From, Subject, Date) with text-overflow: ellipsis truncation, while the detail panel shows the full sender email, full body text, and tags — information that would be far too dense to fit in the table itself. This division of "just enough to scan" versus "everything once selected" is the actual reason the master-detail pattern exists, as opposed to just making the table wider. Pair it with a selectable table if you also need multi-row bulk actions alongside single-row inspection, or a table row context menu for right-click actions on the same list.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSAn inbox-style list renders on the left with an empty detail panel on the right.
  2. 2
    Click a rowThe detail panel instantly fills with that message's full sender, body, and tags.
  3. 3
    Click a different rowThe panel content swaps immediately — the list itself never grows or shifts.
  4. 4
    Note the unread dotUnread rows are bold with a dot; opening one clears both, mirroring a real inbox.
  5. 5
    Check the selection highlightThe currently open row stays visually marked in the list.
  6. 6
    Swap in your dataReplace MESSAGES with your own records; showDetail() is generic over any object shape.

Real-world uses

Common Use Cases

Inbox and messaging layouts
Build the canonical list and reading pane, where clicking a row updates a detail panel instantly rather than expanding inline.
Ticket reading panes
Show full ticket context in an adjacent panel, with a table search highlight helping agents find the right ticket first.
CRM contact browsers
Click a contact row to inspect full details, with one selected id driving both the row highlight and the panel.
Admin record inspectors
Pair with a selectable table when both bulk actions and single-record detail are needed on the same admin screen.
Master-detail versus accordion
Compare with an expandable table that opens details inline, and study the empty state shown before any row is chosen.

Got questions?

Frequently Asked Questions

An expandable row grows taller in place to reveal its detail, pushing every row beneath it down the page — the list's layout changes with every click. This pattern keeps the list a fixed grid and shows detail in a completely separate panel beside it, so clicking different rows never resizes or reflows the list itself — exactly like an email client's message list and reading pane.

Both. showDetail() looks up the clicked message by id and both re-renders the panel from it and sets that message's real unread property to false in the underlying MESSAGES array — so the bold styling and dot indicator that reflect "unread" are driven by an actual data mutation, the same way opening an email in a real inbox marks it read in the underlying mail store, not just visually.

The detail panel shows a dedicated empty state with an icon and a "Select a row to see its details here" message — there's no default-selected first row and no blank panel. This matches the real first-load behavior of a mail client's reading pane, which prompts for a selection rather than guessing one.

No — both are rendered from the same selectedId and the same MESSAGES.find() lookup inside showDetail(), so the highlighted row in the list and the content in the panel always refer to the same record. There's no separate state for "what's highlighted" versus "what's displayed."

Keep selectedId in component state, derive the selected record with a find() over your data array, and render the list (with a selected class check) and the detail panel (or its empty state) both from that same state and derived value — the click handler just needs to set the id, and both halves re-render consistently.