FSAI Design System
Components

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:

  • DetailsGrid
  • CollapsableDetailsGrid
  • DetailsGridCellWrapper
  • DetailsGridCell
  • DetailsGridFormSubmissionCell
  • DetailsGridAddressCell
  • DetailsGridDateRangeCell
  • DetailsGridAssetCell
  • DetailsGridListCell

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

PartPurpose
DetailsGridResponsive grid shell. One column by default, two columns from sm upward.
CollapsableDetailsGridShared accordion section that renders a titled DetailsGrid inside AccordionContent.

Common Cells

PartPurpose
DetailsGridCellWrapperGeneric cell shell with standard surface, label, optional icon, and optional action button.
DetailsGridCellSmall read/edit text field cell. Good for straightforward string or number fields.
DetailsGridFormSubmissionCellTyped field cell driven by a PortalFieldType-style type prop for values such as text, email, phone, date, select, multiselect, currency, and booleans.
DetailsGridAddressCellStructured address editor and display cell.
DetailsGridDateRangeCellPaired start/end date cell.
DetailsGridAssetCellAsset selection and display cell tied to asset workflows.
DetailsGridListCellEditable list-style cell for repeated text items.

Props

DetailsGrid

PropTypeDefaultDescription
childrenReactNodeRequired. Grid cells or wrappers.
classNamestringAdditional grid classes. Often used for spacing or column span overrides on descendants.

CollapsableDetailsGrid

PropTypeDefaultDescription
titlestringRequired section title.
subtitleReactNodeOptional subtitle below the title.
childrenReactNodeRequired. Usually DetailsGrid cells.
defaultOpenbooleanfalseInitial accordion state.
localStorageKeystringPersists open state using the internal collapsable_details_grid_* storage prefix.

DetailsGridCell

PropTypeDefaultDescription
labelstringRequired cell label.
displayValuestring | nullRead-only value shown when isEditing is false. Falls back to -.
isEditingbooleanSwitches the cell into input mode.
InputComponentReactNodeCustom field UI instead of the default Input.
typeInputProps['type']Input type for the built-in field.
errorstringPassed to the built-in Input.
placeholderstringBuilt-in input placeholder.
suffixstringBuilt-in input suffix.
classNamestringAdditional wrapper classes.

DetailsGridFormSubmissionCell

PropTypeDefaultDescription
typePortalFieldTypeRequired. Controls which editor and display behavior is used.
labelstringVisible field label.
valueFieldSubmissionValueCurrent field value.
onChange(value) => voidLive change handler.
onBlur(value) => voidCommit-on-blur handler used in many dashboard screens.
hasEditPermissionbooleanControls 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.
prefixstringPrefix shown in read-only and edit states where supported.
suffixstringSuffix shown in read-only and edit states where supported.
classNamestringAdditional wrapper classes.

Standard Usage Patterns

Settings Card Details

Common in workspace and organization settings:

  • Card
  • Card.Body
  • DetailsGrid
  • mostly DetailsGridFormSubmissionCell
  • occasional DetailsGridAddressCell

Panel Detail Sections

Common in panels with many field groups:

  • repeated CollapsableDetailsGrid sections
  • defaultOpen on the highest-priority section
  • localStorageKey when section state should persist between visits
  • className="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:

PatternPathNotes
Settings details cardfsai/apps/brand-dashboard/src/pages/BrandWorkspaceSettings/BrandProfileDetails/BrandProfileDetails.tsxCanonical DetailsGrid with many DetailsGridFormSubmissionCell items plus DetailsGridAddressCell.
Panel overview sectionsfsai/apps/brand-dashboard/src/pages/LinkTracking/components/LinkTrackingPanel.tsxMixes plain cells, wrappers, and collapsible sections inside a panel workflow.
Finder result detailsfsai/apps/brand-dashboard/src/pages/Marketing/Finder/FinderResultPanel.tsxRepeated CollapsableDetailsGrid sections for dense lead details.
Deal overview sectionsfsai/apps/brand-dashboard/src/modules/deals/components/DealOverviewCard.tsxUses wide rows and richer field combinations inside collapsible groups.
Compliance detail sectionsfsai/apps/brand-dashboard/src/components/StateCompliancePanel/StateCompliancePanelDetails/StateCompliancePanelDetails.components.tsxShows custom wrapper content and picker-driven cells inside the standard shell.
Organization settings detailsfsai/apps/brand-dashboard/src/pages/OrganizationSettings/OrganizationSettingsDetails/OrganizationSettingsDetails.tsxAnother canonical settings-style detail grid.

Important Conventions

  • DetailsGrid is not an items-driven read-only list component. It is a layout wrapper for explicit child cells.
  • CollapsableDetailsGrid is intentionally spelled Collapsable in the API. Match the exported name exactly.
  • The default grid is one column on small screens and two columns from sm upward.
  • Use className="sm:col-span-2" on a cell when content should span the full row.
  • DetailsGridFormSubmissionCell is the main standardized field cell when your field maps cleanly to one of the supported PortalFieldType values, even if the backing data is a regular domain model field.
  • hasEditPermission commonly controls whether a field stays read-only or becomes interactive.
  • Long text in DetailsGridFormSubmissionCell supports collapse and expand behavior in read-only mode.
  • DetailsGridCellWrapper can be used outside DetailsGrid, but doing so opts out of the standard responsive layout.

Guidelines

  • Do use DetailsGrid for dense labeled metadata and inline editing surfaces
  • Do use CollapsableDetailsGrid for repeated sections in panels and other long detail views
  • Do use DetailsGridCellWrapper for custom content that still needs the standard surface and label treatment
  • Do use DetailsGridFormSubmissionCell when a field maps cleanly to its supported typed editors and display modes
  • Don't invent custom two-column detail shells when DetailsGrid already fits
  • Don't treat DetailsGrid as a simple read-only key-value table API

On this page