Build a row-detail inspector sidebar
Show full Northwind record details on cell click — opens a sidebar with the row expanded.
Published Aug 4, 2025
Northwind’s Clients sheet has grown wide — contact details, account status,
notes, renewal dates — and reading a single client now means scrolling
sideways across a dozen columns or freezing panes and squinting. Wide sheets
are hard to read one record at a time, which is exactly when you most need to.
This automation turns any row into a clean, vertical card. Click a cell in the
Clients sheet and a sidebar opens showing that row’s full record as a tidy
list of field-and-value pairs. There is nothing to run and no menu to click —
selecting a cell is the whole interaction.
What you’ll need
- A sheet named
Clientswith a header row in row 1. Every header becomes a field label in the sidebar, so name your columns clearly (name,email,status, and so on). - A second file in the Apps Script project named
Inspectorof type HTML (use File > New > HTML file and name itInspector). - Nothing else — there are no API keys and no extra sheets to create.
The trigger
// The sheet the inspector watches. Selections on any other sheet
// are ignored.
const TARGET_SHEET = 'Clients';
/**
* Simple trigger that fires whenever the user changes their selection.
* If the selection is on the Clients sheet, it opens the inspector for
* the selected row.
*
* @param {Object} e The selection-change event object.
*/
function onSelectionChange(e) {
// 1. Ignore selections on every sheet except the target.
if (e.range.getSheet().getName() !== TARGET_SHEET) return;
// 2. Open the inspector for the row the user just landed on.
showInspector(e.range.getRow());
}
/**
* Reads a single row, pairs each value with its header, and renders
* the result into the sidebar.
*
* @param {number} row The 1-based row number to inspect.
*/
function showInspector(row) {
const sheet = SpreadsheetApp.getActive().getSheetByName(TARGET_SHEET);
// 1. Skip the header row itself — there is nothing to inspect.
if (row < 2) return;
// 2. Read the header row and the selected row.
const lastCol = sheet.getLastColumn();
const [headers] = sheet.getRange(1, 1, 1, lastCol).getValues();
const values = sheet.getRange(row, 1, 1, lastCol).getValues()[0];
// 3. Zip headers and values into a single {field: value} object.
const record = Object.fromEntries(headers.map((k, i) => [k, values[i]]));
// 4. Render the Inspector template, passing the record into it.
const template = HtmlService.createTemplateFromFile('Inspector');
template.row = record;
// 5. Show the evaluated HTML in a sidebar, titled with the record name.
SpreadsheetApp.getUi()
.showSidebar(template.evaluate().setTitle(record.name || 'Record'));
}
The HTML (Inspector.html)
<!-- Each header/value pair becomes a term/definition in a list.
The <? ... ?> tags are Apps Script scriptlets, evaluated on the
server before the HTML is sent to the sidebar. -->
<dl>
<? for (const [field, value] of Object.entries(row)) { ?>
<!-- <?= ?> prints an escaped value, so sheet content cannot
break the page or inject markup. -->
<dt><?= field ?></dt>
<dd><?= value ?></dd>
<? } ?>
</dl>
How it works
onSelectionChangeis a simple trigger that Apps Script runs every time the user moves their selection in the spreadsheet.- It checks the sheet name and bails out immediately unless the selection is
on the
Clientssheet, so the inspector never pops up elsewhere. showInspectorskips the header row, then reads two ranges: the header row and the selected row, each across every used column.- It zips the headers and the row values together into one object — keys are column names, values are the cell contents for that row.
- It loads the
InspectorHTML template, assigns the record object totemplate.row, and evaluates it. The scriptlet in the template loops over the object and emits a<dt>/<dd>pair for every field. - The evaluated HTML is shown in a sidebar titled with the record’s
name.
Example run
Say the Clients sheet has this row, spread across many columns:
| name | status | plan | renewalDate | owner | |
|---|---|---|---|---|---|
| Acme Co | [email protected] | active | Studio Pro | 2025-11-01 | Priya |
Click any cell in that row and the sidebar opens showing the record stacked vertically, easy to read at a glance:
Acme Co
─────────────
name Acme Co
email [email protected]
status active
plan Studio Pro
renewalDate 2025-11-01
owner Priya
Move the cursor to the next row and the sidebar refreshes instantly to that client — no clicking, no scrolling sideways.
Run it
There is nothing to schedule. onSelectionChange is a simple trigger that
runs automatically.
- Save the project with both files: the script and the
InspectorHTML file. - Open the spreadsheet and click a cell in the
Clientssheet. - The first time, approve the authorisation prompt — after that the sidebar appears on every selection.
Watch out for
- Simple triggers like
onSelectionChangecannot call services that require authorisation in some contexts and have a tight 30-second runtime budget. Reading one row is well within that, but do not add slow work here. - The sidebar reopens on every selection change, which can feel busy if you are dragging across many cells. It is fine for click-to-inspect; it is not meant for rapid navigation.
onSelectionChangeonly fires for the user who has the sheet open in their browser — it does not run for collaborators viewing elsewhere, and it does not work in the mobile Sheets app.- Every value is rendered as text. Dates and numbers appear in their raw stored form, which may differ from the cell’s display formatting.
- The sidebar title uses the
namecolumn. If your sheet has nonamecolumn it falls back to a generic title — rename the column or adjust the fallback inshowInspector.
Related
Build a branded approval interface
Approve Northwind requests through a custom UI — clients click, decision is logged.
Updated Nov 8, 2025
Build an interactive quiz or assessment app
Run Northwind tests with scoring and feedback — questions in a Sheet, results in another.
Updated Nov 4, 2025
Build a multi-page web app with routing
Structure a real Northwind app across views — query-param routing, shared layout.
Updated Oct 31, 2025
Build a form-to-PDF web service
Convert Northwind form submissions to PDFs on the fly — POST in, PDF out.
Updated Oct 27, 2025
Build an expiring secure-download generator
Issue time-limited Northwind links via a web app — token in URL, server-side check.
Updated Oct 23, 2025