Components
The @layers/ui vocabulary, rendered stock, with the house rules that bind each component. Coverage is exhaustive and build-enforced: if a component is not on this page, it is not installed.
The one way to attribute a connected social account: avatar, platform badge, and username in a single row. Account selectors, post footers, anywhere a post or metric names its account.
Add CardThe dashed add tile that leads a grid: plus glyph, optional label and hint. Click to add, or drop files straight onto it when it is wired as an upload target.
Agent BadgeThe mono uppercase chip that attributes work to an agent or area: task rows, chat attributions, deliverable cards. The color is the area accent, so a glance says which agent acted.
AlertInline callouts that stay in the flow of a page or panel: notices, warnings, degraded states. Not for confirmations (AlertDialog) or transient feedback.
Alert DialogA blocking confirmation before a destructive or irreversible action: deleting a post, disconnecting an account, discarding an edit, approving a spend change. The user must explicitly cancel or confirm. If the surface asks a question and the answer commits something, it is this — not a Dialog wearing two buttons.
App IdentityThe Ads counterpart to AccountIdentity: rounded app icon, store badge, and app name in a row. An ad target is an iOS or Android app, and every surface that names one renders it this way.
AttachmentFile and image attachments in chat composers, message threads, and upload lists. The chat ruling requires Attachment instead of Item or a custom card.
Attention BarThe app shell's takeover bar: the product has stopped and one action restores it (a walled workspace, ghost mode, a credit balance under the cheapest generation). Never for a notice that can be ignored; that is Alert, in the flow of a page.
Audio MeterA single-bar volume meter for a playing audio element: a Web Audio AnalyserNode merges both channels into one peak level.
AvatarA person or account identity mark: profile pictures in account rows, message authors, member lists. Groups overlap with AvatarGroup and truncate with AvatarGroupCount.
BadgeShort status markers inline with other content: post state, platform tags, counts. One or two words, read at a glance.
Border BeamA light that travels the border of the one control a surface is trying to hand the user — the "this is the thing to press" signal for a primary CTA that would otherwise read as static content. Owned, not installed: colors come from the brand palette and reduced motion removes the beam.
Brand LogoThe Layers L-mark inside its dark squircle box: the app rail home link, the FullscreenModal header, any surface that signs itself as Layers.
BreadcrumbA page title on a route-navigated app (MMA) when the screen is one level inside a list screen, such as one connection inside Connections. The parent is a link; the current page is the last item. In the product app, stacked canvas sheets are the breadcrumb, so this is not used there.
ButtonAny click action: submits, confirmations, toolbar controls. Text-only or icon-only; the label says exactly what happens.
Button GroupRelated controls fused into one segmented row with flush inner corners: prev/next pairs, split buttons, a count beside its action.
CalendarPicking dates from a month grid (react-day-picker): a single day, multiple days, or a range. Usually rendered inside a Popover; for date plus time use DateTimePicker.
CanvasThe app canvas column: the bg-secondary work surface that fills the space beside the chat pane and hosts the stacking CanvasSheets.
Canvas SheetThe stacking panel system inside the canvas column: every area page is a base sheet, and detail views stack on top of it. Overlays in the app are stacked CanvasSheets, not modals.
CardGrouped content that stands on its own: settings sections, digests, summaries. The default surface for a standalone block with an optional header and footer.
Catalog CardA MediaCard specialization for picker grids: a square thumbnail with a title and optional description in the footer. Used where the user chooses an item, like product catalogs.
ChartThe composable foundation every new Strata chart builds on: ChartContainer scopes a config that maps series keys to CSS variables, and the tooltip/legend pieces render themed. Recharts stays unwrapped; you compose its primitives directly.
ChatThe chat stream vocabulary: MessageScroller keeps the conversation pinned to the live edge, and Marker divides the stream with separators like day markers. Row content (message bubbles) is owned by the consuming surface.
Chat PaneThe universal Elle chat layout: one frame (header, optional banner, the scrollable stream on the shared readable measure, working status bar over the composer) across /chats, the area companions, onboarding, and Cora. Surfaces supply the stream entries, header, and footer; the engine behind them is the surface’s concern.
CheckboxIndependent on/off choices in a form, or multi-select in a list. Each checkbox stands alone; for one-of-many use RadioGroup.
Code blockShowing a copyable snippet — install steps, API examples, generated prompts. One block, one snippet.
ComboboxA searchable pick list (Base UI): filter as you type, then choose. Short fixed lists use Select instead; multi-select with removable chips uses the ComboboxChips family.
CommandA searchable action or navigation list (cmdk): command palettes and pickers that filter their items as you type. CommandDialog wraps the palette form.
Command InlineEmbedded command search inside Dialog content: the same cmdk anatomy in a bordered rounded-md shell that sits flush within a dialog.
ComposerThe "message Elle" input: one auto-growing textarea that renders as a pill on a single line and expands to a rounded multi-line form the moment the text stops fitting. Enter sends; Shift+Enter adds a newline.
Connection CardThe compact tile for one connectable data source in a directory of them. Built to render by the hundred: mark, status, name, one muted line.
Connection PanelThe one surface for a single connection: what it gives you, what you currently have, and the one thing you can do about it. Opened from a ConnectionCard in the directory, connected or not.
Connection Request CardA living, inline request to connect a signal provider. The same card remains in place as a connection moves from available through working, ready, failed, or skipped.
Content CardThe generated-post card: 9:16 media rendered through MediaPlayer with the two-cell ContentCardFooter (account and schedule) beneath, wrapped in the gradient hover glow.
Content Card FooterThe footer under every generation card: one pill per destination, each pairing an account with the time IT goes out. ContentCard, ContentRenderer, and ContentPlaceholder all share it.
Content PlaceholderThe processing and failed states of a content container: a placeholder that holds the grid cell while a generation runs, then hands off to ContentCard when media lands.
Content RendererA near duplicate of ContentCard whose post fields accept null (media_urls, media_type, hook). Reach for it only when your data really is nullable; otherwise use ContentCard.
Data TableEvery tabular area list: accounts, live posts, invoices. One component owns the sticky header, sorting, skeleton loading, row click, selection, and infinite scroll.
Date Time PickerPicking a date and a time together, like scheduling a post: a calendar popover, a time input, and an optional clear button in one row.
Decision DockThe formal tier of the two-tier decision system: a quiet strip pinned above the composer that walks the user through everything the system is blocked on, one decision at a time. Consent moments (tool approvals, plan spend gates) and structured questions (setup wizards, data collection) alike. Never for the conversation’s own casual next beat (that is DecisionPills), and never for approving a document (artifact consent happens on the canvas).
Decision PillsThe decision bar above the composer when the agent needs an answer: exactly one filled recommendation, with any alternatives as subordinate outline buttons.
Decomposition BarOne quantity split into named parts that sum to it — a residual pool broken into reasons, a spend total broken by channel. Reach for it when the reading is "these are all of the same whole", never for progress toward a target.
Destructive Action CardOne action that tears something down, isolated in its own card with the consequence spelled out and a confirmation behind it: disconnect an integration, remove a listing, delete a project. Sits last on a settings surface, below the facts it acts on.
DialogA centered modal for focused content and small forms: renaming a post, editing settings, picking options. Blocking yes/no confirmations use AlertDialog instead.
Dot Field LoaderThe working state of a surface that is loading or generating content — the Brand bento asset folders and the content generation cards. A muted dot matrix with a soft band of lit dots sweeping top to bottom: a scanner moving over work in progress, not a glow blob.
Dropdown MenuA list of actions behind one trigger: row actions on a table, the overflow menu on a card, account switching. Menus hold actions; picking a value for a form field is a Select or Combobox.
Elle AvatarElle wherever she speaks: chat message rows, session headers, SMS mockups. A static black and white Elle mark inside a circle.
Empty StateThe zero-items state of a surface, list, or grid: no posts scheduled yet, no accounts connected. Says what belongs here and gives one way to fill it.
FieldThe layout family for every form: consistent label, description, and error placement around any control. FieldSet and FieldGroup space whole sections; Field spaces one control.
Filter MenuA toolbar filter over SEVERAL values at once: account types, statuses, platforms. One value only? Use Select. A control strip that changes a mode rather than narrowing a list? That is not a filter.
FormReact-hook-form bindings for validated forms: settings panes, dialogs, anything with rules and error messages. The Field family handles layout; Form wires state, ids, and aria attributes.
Fullscreen DialogThe fullscreen builder-overlay chrome: real Dialog semantics (portal, backdrop, Esc, focus trap) on a fixed fullscreen frame with the ElleMark header, a round close button, and an optional fixed footer action bar. Used by the slideshow builders and reference pickers.
Fullscreen Media PreviewThe 9:16 media lightbox inside fullscreen editors and detail sheets: the current slide on a letterboxed canvas with a thumbnail rail, arrow-key and click-to-advance navigation, and an optional per-slide delete.
Fullscreen ModalA full-viewport takeover for creative builders and editors: work that needs the whole screen, not a panel. Portals to document.body with a sticky BrandLogo header, Escape handling, and body scroll lock.
GridAn equal-column arrangement of same-shaped cards inside a sheet or card: paired charts, a side-by-side of two panels. Part of the Elle generative-UI catalog, so agents and developers compose the same primitive.
Hashtag TextareaWriting captions with hashtag autocomplete: typing # opens a suggestion list filtered from a keyword list, built on Textarea plus Popover and Command.
HeadingThe one heading primitive. as picks the outline level for the document structure; variant picks a bundled visual preset from the type scale. The two axes are independent.
InfiniteLoaderThe next-page indicator for an infinitely-scrolling list or grid: generations, research, the creative library, the catalog and content pickers. Render it under the list, guarded on the query's own isFetchingNextPage. For a first load (no rows yet) use skeletons shaped like what is coming, not this; for a full-panel load center a size-8 Spinner in the region.
InputSingle-line text entry in forms: names, links, handles.
Input GroupAn input with something attached: a leading icon, a text prefix, an inline button. One bordered group instead of an input plus floating decorations.
Input OTPEntering a verification code sent by email or SMS: one slot per character, with paste and autofill support (the input-otp library).
LabelNames a form control. Every Input, Textarea, Select trigger, Checkbox, Switch, and RadioGroupItem gets one.
List RowThe conversation and list row: a title with an optional badge, a two-line subtitle, and small agent chips. The chats list is the reference consumer.
Live Post CardA posted piece of content with its live performance: 9:16 media beside a primary stat, a secondary stat list, and a platform/username/date footer. The card for Live Posts grids (social, UGC) and Elle’s generated post lists.
Live Post DetailThe live-post performance detail: a scrolling stats column (metrics grid, views bars, engagement area, audience breakdowns) beside a sticky 9:16 media preview. Purely presentational; every consumer passes ready data.
MarkdownRenders a markdown string (react-markdown plus GitHub-flavored markdown) with the house typography: headings, lists, tables, inline code, and links.
Media CardThe shared clickable media surface: a card with an optional footer and the standardized gradient hover glow. Use it anywhere media renders as a card (library assets, catalogs, products) so hovering media feels the same everywhere.
Media PlayerThe hover-to-play media preview behind every content card: a single image, a multi-image slideshow, or a muted looping video, revealed with a fade once loaded.
Meter ListLabeled progress rows — icon, label, "x of y", track, and an optional muted meta line. The repeated per-group meter a dashboard workstream panel needs.
Nav TabsRoute-linked sub-navigation across an area’s pages (Social → Live Posts / Schedule / Accounts). For in-place view switching inside one surface, use Tabs instead.
Navigation MenuHeader navigation with dropdown panels: the marketing site header is the reference consumer. Triggers read as plain text links; panels morph between items in a shared popover viewport.
Pace ChartGoal progress against an on-track reference: the measured series, a dashed pace line from baseline to target, and the target itself. The plan dashboard is the reference consumer.
Platform IconInline brand marks for the platforms Layers touches: tiktok, instagram, meta (facebook is an alias), github, slack, appstore, googleplay, youtube, linkedin, apple, stripe, revenuecat. The badge inside AccountIdentity and AppIdentity, platform pickers, connect flows.
PlatformTileA third-party provider’s mark on its own brand-colored tile, for surfaces where connections are browsed and chosen — the connections directory above all. For an inline identity mark inside a row, badge, or account line, use PlatformIcon instead: a colored chip is noise there.
PopoverLightweight content anchored to a trigger: a small form, a date picker, an inline explainer. Blocking decisions go to Dialog or AlertDialog; plain labels are Tooltips.
Power ListThe answer to "why would I do this" on any surface that puts a capability behind a setup step: a connection, a phone number to verify, an SDK to install. One sentence per thing the capability buys.
ProgressDeterminate progress toward a known end: an upload, a batch of posts going out. For work of unknown duration use Spinner.
Property ListA read-only set of label/value facts about ONE subject: what a connection is bound to, what an API key’s prefix is, what a post scored. Use it wherever you were about to hand-roll a two-column <dl>.
QR CodeHanding a payload from a desktop screen to the phone in the user’s hand: phone verification (the sms: link that opens Messages prefilled), device pairing, a link that only makes sense on mobile. Always pair it with a plain button that does the same thing, for the people already on that phone.
Radio GroupPicking exactly one option from a short visible list: posting cadence, mode, audience. When the list gets long, use Select.
Rate ChartA compact area chart for percentage rates over time inside a Card size sm, with a gradient fill under the line.
Save BarThe commit row for an inline edit on a page: a table of checkboxes, a settings block, a picker. It sits directly under the thing it commits, right-aligned, and renders only while there are unsaved changes.
ScopeAvatarThe mark for something the user OWNS and switches between — a project, an organization. Its real icon when we hold one, otherwise its first letter on a brand pastel. Use PlatformTile for a third-party provider (that is a vendor’s brand, not the customer’s thing) and AccountIdentity for a social account.
ScopeSwitcherPicking WHICH thing a surface acts on — which project the rail is in, which organization a billing dialog is reading. It is a scope control, not a form field: for choosing a VALUE inside a form, use Select (one of many) or RadioGroup (one of a few).
Section LabelThe house mono uppercase marker for section headings inside panels, tables, and lists.
SelectChoosing one option from a fixed list: platforms, accounts, filters. For searchable or free-form lists reach for Combobox instead.
Select ListPick several, commit once: checkbox rows with a single Save. The generative-UI surface for keeping a subset of generated options (the hook picker); the DecisionDock doctrine applied to a selection instead of a wizard.
SeparatorA hairline divider between adjacent content regions when spacing alone does not read as a boundary.
ShimmerText that represents live, streaming, or thinking work: a "Thinking" line in chat, a status label while an agent runs. The sweep says "in motion" without a spinner.
Signal MeterA quantity already held, read as a gauge — how much of a project’s available signal Layers actually has. Never for work in flight.
SignalCardA board of every outside source a project could be read from, present from the first second and dimmed until it is real. The onboarding canvas is the consumer: the board shows the shape of the whole relationship before the visitor has given anything.
SignalFieldA backdrop for a surface that would otherwise be a flat empty plane and that has a run to report on. Dots scattered across the container are pulled home into the Layers mark as progress advances. The onboarding canvas is the consumer.
SkeletonPlaceholder blocks while real content loads. Mirror the shape of what will render so the layout does not jump when data arrives.
SliderPicking a numeric value, or a range with two thumbs, along a continuum: intensity, budget split.
SpinnerIndeterminate loading with no known end point: a save in flight, a route resolving, a full-panel load. For the next page of an infinitely-scrolling list use InfiniteLoader, never a bare Spinner — it owns the centring and the padding. For determinate work use Progress. To signal an agent is live/working (not loading) use ThinkingOrb; for the streaming chat work-line use WorkingStatus.
Stat CardThe summary row that opens an area page, a dashboard, or a post detail sheet: a run of KPIs, each a label, a formatted value, and optionally what it was doing over a comparison window.
Sticky Section HeaderThe header for each section of a long scrolling list — a day of scheduled posts, a bucket of content. Title left, count right, sticky at the top of the scroll region so the reader always knows which section they are in.
Suggestion PillsEqual-weight conversation starters above the composer: outlined pills that each send a ready-made message. No recommendation is being made; every option carries the same weight.
SwitchA standing binary setting: auto-post, notifications. Use Checkbox when the choice is one of several fields submitted together.
TabsSwitching between peer views inside one surface: Live Posts and Schedule, Preview and Details. For route-linked navigation use NavTabs.
Tag inputFree-text entry that commits tokens into dismissible pills: geo country codes, ad keywords — any list a user types rather than picks. Not for choosing among known options (use Select or SuggestionPills).
TextareaMulti-line text entry: briefs, captions, notes. It grows with its content instead of showing a resize handle.
ThinkingOrbThe glyph on a live agent line — Elle's working status, where a pulsing green dot used to sit. Each state is a distinct animation, so the orb says WHAT is happening (searching, composing, connecting) rather than merely that something is. It is a status indicator, not a loader: for indeterminate loading use Spinner, and for the next page of a list use InfiniteLoader.
ToggleA single pressed or unpressed control: bookmark, show captions. The state lives in the control itself; for a set acting together use ToggleGroup.
Toggle GroupA set of related toggles acting as one control: alignment, view density. For a single standalone control use Toggle.
ToolbarFilterSelectThe standard toolbar filter: choosing one value from a fixed option list to narrow the surface below (status, platform, date range). It is Select pre-shaped for toolbars — flat trigger, 32px, every item in a SelectGroup — so toolbar call sites pass options instead of re-composing the anatomy.
TooltipA short label on hover or focus that names a control or explains a value: what an icon-only button does, what a metric counts.
Track ListA music picker with audio preview — trending tracks a user can hear before committing one to a reel. The catalog surface for the first-experiment music conversation; MediaCard only plays video.
Trend ChartA compact bar chart for count metrics over time (views, likes) inside a Card size sm. The header shows the series total; hovering a bar swaps it for that point.
Vertical Resize HandleThe floating-pill seam between two resizable columns, like the chat/canvas divider. The handle is the visual; the hooks own the drag.
Window SheetThe resizable inspector panel anchored to the right edge: post inspectors, editors, settings panels that live beside the page instead of over its center. Drag the left edge to resize.
Work CardThe in-feed record of one piece of work that was kicked off: what it is, how far it got at starting, and the way to check both. It resolves in place as evidence arrives and then stays, because the record is the point.
WorkingStatusThe streaming work-line shown over the chat composer while Elle is actively working: a small spinner, a shimmer label, and an elapsed-seconds counter. Not a loader (use Spinner) and not the live-agent glyph (use ThinkingOrb).