Settings Row
A label/value/edit row used to compose dense settings pages
import {
SettingsList,
SettingsRow,
} from '@/components/settings-row';
import { Surface } from '@/components/surface';
export default function SettingsRowPreview() {
return (
<Surface elevation="default" padding="sm" className="w-full max-w-2xl">
<SettingsList>
<SettingsRow>
<SettingsRow.Label>Email address</SettingsRow.Label>
<SettingsRow.Value>jane@demo.mercury.com</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
<SettingsRow>
<SettingsRow.Label>Preferred name</SettingsRow.Label>
<SettingsRow.Value>Jane Black</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
<SettingsRow>
<SettingsRow.Label>Date of birth</SettingsRow.Label>
<SettingsRow.Value>01/31/1990</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
<SettingsRow>
<SettingsRow.Label>Job title</SettingsRow.Label>
<SettingsRow.Value className="text-foreground-secondary">
Not set
</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Add</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
</SettingsList>
</Surface>
);
} Source Code
import { cn } from '@/lib/utils/classnames';
const SettingsList = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
className={cn('flex flex-col divide-y divide-border', className)}
{...rest}
/>
);
interface SettingsRowProps extends React.ComponentPropsWithRef<'div'> {
/**
* Adds a subtle, inset hover highlight (rounded, with a small margin around
* the row edges) — Linear / Mercury settings style. On by default.
*/
hoverable?: boolean;
}
const SettingsRow = ({
ref,
className,
hoverable = true,
...rest
}: SettingsRowProps) => (
<div
ref={ref}
className={cn(
'relative grid grid-cols-1 items-start gap-2 px-2 py-4 md:grid-cols-[14rem_minmax(0,1fr)_auto] md:gap-6',
// Inset hover highlight via ::before — the row stays edge-to-edge so the
// divider line still spans full width, but the hover paints inside an
// inset rounded rectangle (mx-1 my-0.5 equivalent).
hoverable &&
'before:pointer-events-none before:absolute before:-inset-x-0.5 before:inset-y-0.5 before:rounded-lg before:bg-foreground/0 before:transition-colors before:duration-(--duration-hover) before:ease-(--ease) hover:before:bg-foreground/4',
// Children stack above the ::before highlight via `relative z-1`.
hoverable && '[&>*]:relative [&>*]:z-1',
className
)}
{...rest}
/>
);
const SettingsRowLabel = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
className={cn(
'font-medium text-base text-foreground leading-relaxed',
className
)}
{...rest}
/>
);
const SettingsRowValue = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
className={cn(
'flex min-w-0 flex-col gap-1 text-foreground text-sm',
className
)}
{...rest}
/>
);
const SettingsRowAction = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
className={cn('flex shrink-0 items-center gap-2', className)}
{...rest}
/>
);
/**
* Inline accent-coloured "Edit" / "Add" link as seen in Mercury settings.
* Render as `<a>` or `<button>` via `asChild` if you need a real interactive
* element. This is a styling shell — pair with whatever element makes sense.
*/
const SettingsRowLink = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'a'>) => (
<a
ref={ref}
className={cn(
'focus-visible:ring-(length:--ring-width) inline-flex items-center gap-1 font-medium text-(--color-border-hover) text-sm ring-ring hover:underline focus-visible:outline-none',
className
)}
{...rest}
/>
);
const CompoundSettingsRow = Object.assign(SettingsRow, {
Label: SettingsRowLabel,
Value: SettingsRowValue,
Action: SettingsRowAction,
Link: SettingsRowLink,
});
export type { SettingsRowProps };
export { CompoundSettingsRow as SettingsRow, SettingsList }; Server component. No
'use client'— settings list row layout; forwards props only.
SettingsRow composes a label, current value, and an inline action (typically
“Edit” or “Add”) into the row pattern used by Mercury, Stripe, and Linear
settings pages. Stack rows inside SettingsList to get a divider between each.
Anatomy
<SettingsList>
<SettingsRow>
<SettingsRow.Label>Email address</SettingsRow.Label>
<SettingsRow.Value>{email}</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
</SettingsList>
API Reference
SettingsList
Extends the div element. Wraps rows and adds dividers between them.
SettingsRow
Extends the div element. A 3-column responsive grid: label / value / action.
| Prop | Default | Type |
|---|---|---|
hoverable | true | boolean |
When hoverable is on, an inset rounded highlight appears on hover — the row
stays edge-to-edge for the divider line, but the hover paints inside a small
margin (Linear / Mercury settings style).
SettingsRow.Label / Value / Action
Extend the div element.
SettingsRow.Link
Extends the a element. Accent-coloured inline link, sized for use as the row
action.
Examples
Default
import {
SettingsList,
SettingsRow,
} from '@/components/settings-row';
import { Surface } from '@/components/surface';
export default function SettingsRowPreview() {
return (
<Surface elevation="default" padding="sm" className="w-full max-w-2xl">
<SettingsList>
<SettingsRow>
<SettingsRow.Label>Email address</SettingsRow.Label>
<SettingsRow.Value>jane@demo.mercury.com</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
<SettingsRow>
<SettingsRow.Label>Preferred name</SettingsRow.Label>
<SettingsRow.Value>Jane Black</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
<SettingsRow>
<SettingsRow.Label>Date of birth</SettingsRow.Label>
<SettingsRow.Value>01/31/1990</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Edit</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
<SettingsRow>
<SettingsRow.Label>Job title</SettingsRow.Label>
<SettingsRow.Value className="text-foreground-secondary">
Not set
</SettingsRow.Value>
<SettingsRow.Action>
<SettingsRow.Link href="#">Add</SettingsRow.Link>
</SettingsRow.Action>
</SettingsRow>
</SettingsList>
</Surface>
);
} Previous
Select
Next
Sidebar