Components / Connection Card
Connection Card
The compact tile for one connectable data source in a directory of them. Built to render by the hundred: mark, status, name, one muted line.
import { ConnectionCard, ConnectionCardGrid } from '@layers/ui/connection-card'Rendered stock
House rules
- Every state carries exactly one action, a named button in CardFooter: Connect when available, Manage when connected, Reconnect when it needs the user. An unconnected tile never leaves its call to action implied by a glyph or by the card being pressable, because a user scanning a wall of tiles should not have to guess what to press.
- The root is never a button, in any state. The card is not pressable; its footer button is the single focus stop. An action button nested inside a pressable card is an a11y defect, so the CTA wins and the whole-tile press goes.
- What separates the states is INK and a badge, never a frame (2026-07-31). Every tile is the same borderless Card: available mutes its header and content and shows no badge, the settled states carry one. available used to take AddCard's 2px dashed frame, which outlined most of the grid and read as chunky at any real catalog size — and once every provider had a full-color brand mark, the marks were doing the work the frame was invented to do. Mark, name, description and button never move between states, so the grid does not jump as a tile connects. The card itself has no hover response, because the card is not the affordance; its button is.
- The action button is outline, never destructive. Connecting and managing are routine and reconnecting is recovery; red is reserved for dangerous actions.
- note is the one tile with no action: a STAGED source the surface is naming before the user can act on it. Onboarding stages the sources a visitor's intake answers imply, while they still have no account to hang a credential on, and the tile says "Connect in your workspace" where the button would be. The footer never empties, so a grid mixing staged and live tiles keeps its rhythm. A disabled Connect was the easy version and it is the one rules.md forbids: a dead affordance is removed, not disabled. This is not an escape hatch for a caller that would rather explain than act — if the action can run on the surface, it renders.
- available renders no badge. In a grid of hundreds, a "Not connected" chip on every unconnected tile is noise, and the muted ink already says it. The word still reaches assistive tech through the status region.
- Status color follows the status contract: connected is the success variant (ok), attention is warning, error is destructive. Never a raw color utility and never a raw hex.
- statusLabel overrides the status word when the caller knows the specific thing that is wrong ("Token expired"). It names a state, not an action, because it is also the accessible status; the action is actionLabel’s job.
- A provider is a name plus, when we hold one, provider.platform. There is NO per-call-site icon escape hatch (2026-07-31). There used to be — a ReactNode slot every unbranded provider filled with a Lucide glyph — and it produced exactly what rules.md forbids: a megaphone standing in for Google Ads, a chart for PostHog, read by anyone scanning the grid AS those companies' marks. Omit platform and PlatformTile degrades to a monogram of the provider's own name, which claims nothing false, in ONE place instead of at every call site. Never hand-draw a brand mark.
- There is no featured or banner arrangement, and no per-importance variant of any kind (founder direction 2026-08-01). One existed for the Layers SDK — full width, three columns, larger title — and it read as an ad pinned over the directory rather than a member of it. Every source states its case in the same tile and its own panel. If a source needs to outrank the others, that is what section order and the attention-first sort are for.
- Name and secondary line each truncate to one line. detail replaces description on a connected tile when there is something truer to say ("3 accounts"); count renders that line for you when detail is absent.
- ConnectionCardGrid is the container: auto-fill columns with a 240px minimum and equal rows, so tiles stay the same height however their states are mixed and every footer button lands on the same line. Grid is fixed 1-4 columns and cannot express it.