CXB Console’s reusable building blocks live in src/components/ui/. Pages compose these primitives instead of hand-rolling inputs, modals, or tables, which keeps theming (CSS variables) and behavior consistent across brands.

UI Primitives

Each primitive is a small typed component with a CSS module of the same name.
ComponentFileRole
TextInputcomponents/ui/TextInput.tsxText/number/url/email/password/date/time input with suffix, error, onBlur
TextAreacomponents/ui/TextArea.tsxMultiline input with variant, monospace, showCount, maxHeight
Selectcomponents/ui/Select.tsxDropdown taking options: {label, value}[]
Togglecomponents/ui/Toggle.tsxBoolean switch with a label
Slidercomponents/ui/Slider.tsxRange input with min/max/step/showValue
TagInputcomponents/ui/TagInput.tsxMulti-value tag entry
FormFieldcomponents/ui/FormField.tsxLabel + helpText + error wrapper around an input
Sectioncomponents/ui/Section.tsxTitled, optionally collapsible panel with a badge slot
SectionGroupcomponents/ui/SectionGroup.tsxGrouped sections with title/description/icon/variant
Modalcomponents/ui/Modal.tsxAnimated dialog with backdrop, Escape-to-close, body scroll lock
Badgecomponents/ui/Badge.tsxStatus pill with success/primary/neutral/danger variants
DataTablecomponents/ui/DataTable.tsxGeneric sortable, paginated table
DateRangeFiltercomponents/ui/DateRangeFilter.tsxPreset + custom date range picker
EmptyStatecomponents/ui/EmptyState.tsxEmpty placeholder with optional action
Skeletoncomponents/ui/Skeleton.tsxLoading placeholder (row/card variants)
TextPreviewcomponents/ui/TextPreview.tsxTruncated text with expand
SoftAuroracomponents/ui/SoftAurora.tsxDecorative brand-colored background
All visual styling references CSS variables (var(--primary), var(--surface), var(--line), etc.), which the white-label build injects per brand.

DataTable

DataTable<T> is the generic table used by list pages such as Call Logs. Props:
PropTypeNotes
columnsColumn<T>[]Each has key, header, optional render, sortable, width
dataT[]Row data
onRowClick(item: T) => voidOptional; makes rows clickable
loadingbooleanRenders skeleton rows
pageSizenumberDefaults to 10
emptyMessagestringShown when data is empty
Behavior:
  • Sorting is client-side. Clicking a sortable header toggles asc/desc; numeric values compare numerically, everything else via localeCompare. Nulls sort last.
  • Pagination is client-side and only appears when data.length > pageSize.
  • render overrides cell content; without it the raw value is stringified.
DataTable paginates the array it is given. Pages with server-side pagination (for example Call Logs, which fetches 50 rows per server page) keep the table’s pageSize aligned with the fetch size and drive paging through their own state so the table is not double-paginating a partial dataset.

DateRangeFilter

DateRangeFilter renders preset buttons — Today, Yesterday, 7 Days, Week to Date, Month to Date, Custom — plus two <input type="date"> fields when Custom is selected. It computes a { from, to } range in the supplied timezone via computeDateRange (from utils/timezone) and calls onChange whenever the range changes.

The Number-Input Blur Pattern

Number fields never parse on every keystroke. Instead they keep an empty intermediate string in state while typing and commit a default on blur. This avoids parseInt snapping the field to 0 (or NaN) mid-edit. The canonical shape (from StepIdentity re-engagement gaps):
<TextInput
  value={form.re_engagement_first_gap === 0 ? '' : form.re_engagement_first_gap}
  onChange={(v) => set('re_engagement_first_gap', v === '' ? 0 : (Number(v) || 0))}
  onBlur={() => { if (!form.re_engagement_first_gap) set('re_engagement_first_gap', 8); }}
  type="number"
  suffix="s"
/>
Rules this encodes:
  • A value of 0 displays as an empty string so the field can be cleared.
  • onChange stores 0 for empty input and never throws on partial entry.
  • onBlur restores a sensible default when the field is left blank.
The same pattern appears in the Tool Builder timeout field (ToolBuilder.tsx), which defaults to 8 seconds on blur. Reuse it for any numeric config field.

App Shell & Routing

Where these primitives get rendered.

White-Label Build

How CSS variables are themed per brand.

Call Logs

DataTable and DateRangeFilter in use.