Record Panel
Attio's right-side record peek — slides in over the grid to show one record's fields.
The peek panel Attio opens when you click into a row: a 420px sheet that slides in from the right over the main content, showing one record's fields as label/value rows. Measured from the live app — a 52px header (favicon/logo + name + close), a scrolling body of typed fields (tags keep their colour, URLs link, numbers format), and a soft left-edge shadow.
Preview
Hover any row below and click the ↗ button that appears on the Company cell to peek the record; Esc or the × closes it.
Installation
bun add crispimport "crisp/styles.css";
import { RecordPanel } from "crisp";Usage
RecordPanel is driven by a single record prop — pass the row to open, or null to close. It renders nothing when record is null, so keep it mounted and flip the state. Wire it to a table's onOpenRecord:
import { RecordPanel, RecordsTable, defaultColumns, type Row } from "crisp";
import * as React from "react";
export function Companies() {
const [open, setOpen] = React.useState<Row | null>(null);
return (
// a position: relative container — the panel positions absolutely inside it
<div style={{ position: "relative", height: "100%" }}>
<RecordsTable onOpenRecord={setOpen} />
<RecordPanel
record={open}
columns={defaultColumns}
onClose={() => setOpen(null)}
/>
</div>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
record | Row | null | — | The record to show. null renders nothing (panel closed). |
columns | Column[] | — | Column definitions — drives the field rows (the entity column becomes the header). |
onClose | () => void | — | Called by the × button and the Esc key. |
className | string | — | Extra class on the panel root. |
Notes
- Positioning. The panel is
position: absolute; inset-block: 0; right: 0, so it must live inside aposition: relativeancestor — the app's main content area, or the demo frame above. It overlays rather than pushing the grid. - Field rendering. The column whose
typeisentitysupplies the header (favicon + name); every other column renders a label/value row. Values reuse the table's typed renderers — colour-coded tags,toLocaleString()numbers, brand-colored links — and show a muted Empty when there's no value. - Enter animation. It slides in from the right via
@starting-style(translateX(100%)→0), the same technique the Command menu uses. - Escape to close. While open it listens for Esc; the listener is removed when closed.
See it composed into the full page in the Companies page example.