DetailsGrid
Standardized two-column detail layout for dense read and edit surfaces in dashboard cards and panels.
Overview
DetailsGrid is the shared-ui layout used across the brand dashboard for dense labeled detail cells.
It is most often used for:
- editable metadata sections inside cards
- read-and-edit detail panels
- collapsible detail groups with consistent card-like cells
- portal-field driven entity details
The exported building blocks are:
DetailsGridCollapsableDetailsGridDetailsGridCellWrapperDetailsGridCellDetailsGridFormSubmissionCellDetailsGridAddressCellDetailsGridDateRangeCellDetailsGridAssetCellDetailsGridListCell
In practice, DetailsGrid is a layout system as much as a single component.
Basic Usage
import {
DetailsGrid,
DetailsGridCell,
DetailsGridCellWrapper,
DetailsGridFormSubmissionCell,
} from '@fsai/shared-ui';
<DetailsGrid>
<DetailsGridCell label="Brand Name" displayValue={brand.name} />
<DetailsGridCellWrapper label="Status">
<Badge label={brand.isActive ? 'Active' : 'Inactive'} color="green" />
</DetailsGridCellWrapper>
<DetailsGridFormSubmissionCell
type="email"
label="Brand Email"
value={brand.email}
hasEditPermission={canEdit}
onBlur={(value) => updateBrand({ email: value?.toString() })}
/>
<DetailsGridCellWrapper className="sm:col-span-2" label="Notes">
<p className="text-regular">{brand.notes || '-'}</p>
</DetailsGridCellWrapper>
</DetailsGrid>DetailsGrid itself just provides the responsive grid. The consistency comes from the cell components placed inside it.
Collapsible Sections
Use CollapsableDetailsGrid when a detail section should open and close like a standard accordion section:
import {
CollapsableDetailsGrid,
DetailsGridFormSubmissionCell,
} from '@fsai/shared-ui';
<CollapsableDetailsGrid
title="Basic Information"
subtitle="Editable franchise details"
defaultOpen
localStorageKey={`franchise-${franchise.id}-basic-information`}
>
<DetailsGridFormSubmissionCell
type="short-text"
label="Legal Name"
value={franchise.legalName}
hasEditPermission={canEdit}
onBlur={(value) => updateFranchise({ legalName: value?.toString() })}
/>
<DetailsGridFormSubmissionCell
type="phone"
label="Phone"
value={franchise.phone}
hasEditPermission={canEdit}
onBlur={(value) => updateFranchise({ phone: value?.toString() })}
/>
</CollapsableDetailsGrid>This is the common pattern for long detail panels with multiple standardized sections.
Component API
Root Layout
| Part | Purpose |
|---|---|
DetailsGrid | Responsive grid shell. One column by default, two columns from sm upward. |
CollapsableDetailsGrid | Shared accordion section that renders a titled DetailsGrid inside AccordionContent. |
Common Cells
| Part | Purpose |
|---|---|
DetailsGridCellWrapper | Generic cell shell with standard surface, label, optional icon, and optional action button. |
DetailsGridCell | Small read/edit text field cell. Good for straightforward string or number fields. |
DetailsGridFormSubmissionCell | Typed field cell driven by a PortalFieldType-style type prop for values such as text, email, phone, date, select, multiselect, currency, and booleans. |
DetailsGridAddressCell | Structured address editor and display cell. |
DetailsGridDateRangeCell | Paired start/end date cell. |
DetailsGridAssetCell | Asset selection and display cell tied to asset workflows. |
DetailsGridListCell | Editable list-style cell for repeated text items. |
Props
DetailsGrid
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Required. Grid cells or wrappers. |
className | string | — | Additional grid classes. Often used for spacing or column span overrides on descendants. |
CollapsableDetailsGrid
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Required section title. |
subtitle | ReactNode | — | Optional subtitle below the title. |
children | ReactNode | — | Required. Usually DetailsGrid cells. |
defaultOpen | boolean | false | Initial accordion state. |
localStorageKey | string | — | Persists open state using the internal collapsable_details_grid_* storage prefix. |
DetailsGridCell
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Required cell label. |
displayValue | string | null | — | Read-only value shown when isEditing is false. Falls back to -. |
isEditing | boolean | — | Switches the cell into input mode. |
InputComponent | ReactNode | — | Custom field UI instead of the default Input. |
type | InputProps['type'] | — | Input type for the built-in field. |
error | string | — | Passed to the built-in Input. |
placeholder | string | — | Built-in input placeholder. |
suffix | string | — | Built-in input suffix. |
className | string | — | Additional wrapper classes. |
DetailsGridFormSubmissionCell
| Prop | Type | Default | Description |
|---|---|---|---|
type | PortalFieldType | — | Required. Controls which editor and display behavior is used. |
label | string | — | Visible field label. |
value | FieldSubmissionValue | — | Current field value. |
onChange | (value) => void | — | Live change handler. |
onBlur | (value) => void | — | Commit-on-blur handler used in many dashboard screens. |
hasEditPermission | boolean | — | Controls whether the field is editable or read-only. |
options | { value: string; label: string }[] | — | Required for select-like field types. |
validation | { pattern?, required?, message? } | — | Lightweight validation for text-style types. |
prefix | string | — | Prefix shown in read-only and edit states where supported. |
suffix | string | — | Suffix shown in read-only and edit states where supported. |
className | string | — | Additional wrapper classes. |
Standard Usage Patterns
Settings Card Details
Common in workspace and organization settings:
CardCard.BodyDetailsGrid- mostly
DetailsGridFormSubmissionCell - occasional
DetailsGridAddressCell
Panel Detail Sections
Common in panels with many field groups:
- repeated
CollapsableDetailsGridsections defaultOpenon the highest-priority sectionlocalStorageKeywhen section state should persist between visitsclassName="sm:col-span-2"for long text or wide structured cells
Mixed Read And Edit Cells
Use DetailsGridCellWrapper when the content is not a standard form field:
- badges
- links
- custom action affordances
- picker-driven custom values
- rich read-only formatting
Brand Dashboard Usage Patterns
Representative usages:
| Pattern | Path | Notes |
|---|---|---|
| Settings details card | fsai/apps/brand-dashboard/src/pages/BrandWorkspaceSettings/BrandProfileDetails/BrandProfileDetails.tsx | Canonical DetailsGrid with many DetailsGridFormSubmissionCell items plus DetailsGridAddressCell. |
| Panel overview sections | fsai/apps/brand-dashboard/src/pages/LinkTracking/components/LinkTrackingPanel.tsx | Mixes plain cells, wrappers, and collapsible sections inside a panel workflow. |
| Finder result details | fsai/apps/brand-dashboard/src/pages/Marketing/Finder/FinderResultPanel.tsx | Repeated CollapsableDetailsGrid sections for dense lead details. |
| Deal overview sections | fsai/apps/brand-dashboard/src/modules/deals/components/DealOverviewCard.tsx | Uses wide rows and richer field combinations inside collapsible groups. |
| Compliance detail sections | fsai/apps/brand-dashboard/src/components/StateCompliancePanel/StateCompliancePanelDetails/StateCompliancePanelDetails.components.tsx | Shows custom wrapper content and picker-driven cells inside the standard shell. |
| Organization settings details | fsai/apps/brand-dashboard/src/pages/OrganizationSettings/OrganizationSettingsDetails/OrganizationSettingsDetails.tsx | Another canonical settings-style detail grid. |
Important Conventions
DetailsGridis not anitems-driven read-only list component. It is a layout wrapper for explicit child cells.CollapsableDetailsGridis intentionally spelledCollapsablein the API. Match the exported name exactly.- The default grid is one column on small screens and two columns from
smupward. - Use
className="sm:col-span-2"on a cell when content should span the full row. DetailsGridFormSubmissionCellis the main standardized field cell when your field maps cleanly to one of the supportedPortalFieldTypevalues, even if the backing data is a regular domain model field.hasEditPermissioncommonly controls whether a field stays read-only or becomes interactive.- Long text in
DetailsGridFormSubmissionCellsupports collapse and expand behavior in read-only mode. DetailsGridCellWrappercan be used outsideDetailsGrid, but doing so opts out of the standard responsive layout.
Guidelines
- Do use
DetailsGridfor dense labeled metadata and inline editing surfaces - Do use
CollapsableDetailsGridfor repeated sections in panels and other long detail views - Do use
DetailsGridCellWrapperfor custom content that still needs the standard surface and label treatment - Do use
DetailsGridFormSubmissionCellwhen a field maps cleanly to its supported typed editors and display modes - Don't invent custom two-column detail shells when
DetailsGridalready fits - Don't treat
DetailsGridas a simple read-only key-value table API