Composites are the layer above primitives. They live inDocumentation Index
Fetch the complete documentation index at: https://docs.yourhq.ai/llms.txt
Use this file to discover all available pages before exploring further.
apps/ui/src/components/shared/ and encode product-level decisions: how a list is filtered, how a detail surface is laid out, how a confirm dialog phrases its tones, how an empty state looks. Every feature module — CRM, tasks, agents, knowledge, collections, routines — composes from these.
The rule for adding to shared/: a component belongs here when it solves the same problem in two or more modules. One-module solutions live inside the feature module. Stylistic primitives belong in ui/.
Page structure
The pieces that frame every screen.PageHeader, PageSection
shared/page-header.tsx
The standard top of every dashboard route. Icon, title, description, primary action, secondary actions, optional meta and tabs. PageSection is its in-page sibling for grouping content under a heading and optional action button. Use these on every route — bespoke headers fragment the visual rhythm of the app.
HeaderBar
shared/header-bar.tsx
The horizontal bar at the top of the dashboard shell. Carries breadcrumbs (with UUID → entity-name resolution), theme toggle, notifications, user menu. Owned by the shell — feature code should not mount its own header bar.
SidePanel
shared/side-panel.tsx
The right-sliding sheet for sustained record editing — when the user is browsing a list and adding or editing one of its rows. Width presets md (480px), lg (560px, default), xl (720px). Sticky footer for actions. Pick by user mode, not field count: SidePanel for record management, Dialog for quick capture or focused decisions — see creation and editing.
DetailSidebar, DetailSidebarMobile, DetailSidebarSection
shared/detail-sidebar.tsx
The 280px right rail used on heavy detail pages (agent, gateway, knowledge). Sticky on desktop, drawer on mobile, both backed by the same DetailSidebarSection children so content authors don’t write the layout twice.
DetailHeader
shared/detail-header.tsx
The header bar inside a detail view: back button, breadcrumb, action buttons (copy, archive, delete), title with inline-edit support. Distinct from the global HeaderBar.
Lists and tables
DataTable
shared/data-table.tsx
TanStack-backed table. Sortable columns, sticky headers, configurable row heights (compact / normal / comfortable), row click handlers, loading skeleton fallback, empty-state slot. Every table view in the app is a DataTable — never render Table directly for data lists.
FilterBar
shared/filter-bar.tsx
The horizontal control strip above lists. Search input on the left, filter controls in the middle, action buttons on the right, item count on the far right. Composable — modules pass their own filter controls as children.
ColumnToggle
shared/column-toggle.tsx
Dropdown menu for showing/hiding columns. Groups standard fields and custom fields separately, with a “reset to defaults” action. State is owned by the use-column-visibility hook and persisted to localStorage.
ArchiveToggle
shared/archive-toggle.tsx
The “show archived” filter. Reused across CRM, tasks, knowledge, collections so the affordance is the same everywhere.
InlineCreateRow
shared/inline-create-row.tsx
A row at the bottom of a list (or kanban column) that turns into an input on click — Enter creates, Escape cancels. The inline counterpart to opening a SidePanel. Use for fast, single-field creates (a task title, a folder name).
Navigation and search
CommandPalette
shared/command-palette.tsx
The Cmd+K palette. cmdk-based. Sections when no query: Recent, Navigation, Collections, Quick Actions. With a query: grouped search results across knowledge, knowledge chunks, tasks, contacts, collections, agents, routines. Recent items persist via localStorage. New navigation entries register here, not in a parallel registry.
KeyboardShortcutsProvider, useShortcuts, KeyboardShortcutsHelp
shared/keyboard-shortcuts.tsx
The global shortcut registry. G-then-letter navigation with an 800ms double-tap window, ? to open the help sheet, input-aware (skips when focus is in INPUT, TEXTAREA, or contentEditable). All app-wide shortcuts register here so users have one place to discover them.
ModulesContext
shared/modules-context.tsx
Provides which modules are enabled for the current workspace (CRM, tasks, agents, knowledge, collections, routines). Sidebar groups, command palette navigation, and keyboard shortcuts all gate on this context — never check workspace settings directly inside a feature component.
Forms and fields
DynamicField, DynamicFieldGroup
shared/dynamic-field.tsx, shared/dynamic-field-group.tsx
Renders a form field from a FieldDefinition (text, number, select, multi-select, date, boolean, url, email, phone, rich-text, relation). Custom fields on contacts, organizations, tasks, and collections all flow through this. DynamicFieldGroup lays out a related set of fields with a shared label.
EntityLinkPicker, EntityLinkList
shared/entity-link-picker.tsx, shared/entity-link-list.tsx
The polymorphic linking UI. EntityLinkPicker is a popover-with-search that links the current entity to any other (contact, organization, task, knowledge item, URL, file). EntityLinkList displays linked entities as removable chips. The entity_links table backs both.
FileDropZone
shared/file-drop-zone.tsx
Drop-and-pick file upload with preview, used by knowledge file uploads, CRM imports, and avatar pickers. Handles drag-over state, file-type validation, and progress.
Trees
FolderTree
shared/folder-tree.tsx
Recursive folder UI built on @dnd-kit. Expand/collapse state persists to localStorage, inline rename, context menu for create/rename/delete/icon-pick, item counts per folder. Used by knowledge folders today; the canonical drag-and-drop pattern for any future tree.
Confirmations and feedback
ConfirmDialog, ConfirmDeleteDialog
shared/confirm-dialog.tsx, shared/confirm-delete-dialog.tsx
Tone-aware confirmation modal. Tones: default (neutral), warning (amber), destructive (red). Auto-swaps the icon, the confirm button variant, and the busy spinner during async confirms. ConfirmDeleteDialog is a thin preset for deletes — use it for anything irreversible.
EmptyState
shared/empty-state.tsx
The blank-list pattern. Variants: default (welcoming, with primary action), filtered (with “Clear filters” secondary action). compact mode for inline contexts (sidebars, modals). Always include an icon, title, and description; let users do something next.
LoadingSkeleton
shared/loading-skeleton.tsx
Five presets: table (header + body rows with realistic column widths), cards (responsive grid), list (icon + text + meta rows), feed (avatar + text + timestamp), detail (grouped section blocks). Match the skeleton to the layout it replaces — never use a generic spinner where a layout skeleton fits.
Banners
SchemaVersionBanner
shared/schema-version-banner.tsx
The top-of-page banner that appears when the active Supabase database’s schema lags the UI’s expected migration set. Links to the migration guide. The only “blocking” inline alert in the product — most feedback uses toasts.
When to add a composite
Three-question test:- Does this exist in two or more modules already? If you’re about to copy something from
crm/intotasks/, that’s the threshold. Lift it intoshared/first. - Is the API stable? Composites encode shape decisions. If you’re not sure of the props yet, leave it inside the feature for one more iteration before promoting.
- Does it depend on anything outside
ui/,shared/,lib/utils, and React? Composites must not import from feature modules. If yours needs a feature hook, the abstraction is wrong — pass the data in.
shared/ with the existing naming (kebab-case file, PascalCase component, types colocated or imported from lib/). If any are no, keep it inside the module for now.
