Skip to content

Getting started

Common workarounds

What agents rebuild by hand, and the component or rule that already replaces it.

If you are about to write CSS, a setTimeout, a wrapper div, a local copy of a component or a // ca-ui-workaround, check this table first. Every row below exists on main and has an open workaround in a real app behind it.

Imports are from @codeatlasdev/ui unless the last column names a subpath.

You are about to write Use this instead Where
A hand-written <a target="_blank" rel="noopener"> ExternalLink: sets rel, shows the icon, adds a localized “opens in a new tab” ExternalLink
A CSV or JSON download built with Blob and an anchor ExportMenu for a button, or toCsv, toJson and downloadFile for your own trigger ExportMenu
dialog.ca-dialog--split:has(.x) { width: …; height: … }, a .ca-dialog__body { display: flex } rule and a 639px media query to go full screen <Dialog size="split" splitSize={{ width, height }} splitColumns="2fr 3fr" fullscreenBelow="sm"> Dialog
.ca-dnd-indicator { display: none } to drop the insertion line of a board column sortable({ drop: 'container' }) (the column is the target, no line, to.index 0) Drag and drop
confirm() or a hand-made confirm dialog AlertDialog: onconfirm may be async, plus destructive and pending AlertDialog
Appending streamed rows (SSE, WebSocket, a bulk job) to an array and rendering them LiveList: batched announcements, follow-the-tail that pauses on scroll, never moves focus LiveList
setTimeout(() => input.focus()) for a field in a new view primeKeyboard() in the tap handler, then use:autofocus on the field Mobile, @codeatlasdev/ui/actions
Stack gap="4" around fields inside a form FormSection layout="grid", "list" or "stack" AppForm
A local brand strip on auth pages, or a local brand name beside a custom logo AuthLayout: logoMark, logoName and mobileBrand. The brand snippet replaces the mark and the default name; logoName shows beside it only when you set it AuthLayout
A position: fixed full-screen mobile view MobilePane MobilePane
A sticky save bar StickyActions, or the footer snippet of AppForm StickyActions
A .cover { aspect-ratio: 16 / 9; object-fit: cover } class on an image, or a padding-top hack around an iframe <Image ratio={16 / 9}> for a picture (fit="contain" letterboxes), <AspectRatio ratio={16 / 9}> for a video or an embed Image, AspectRatio
A CSS grid with a drag handle and mousemove listeners for a resizable side panel ResizablePanels with ResizablePanel and ResizableHandle: keyboard resize, minSize / maxSize, persist ResizablePanels
A overflow-x: auto; scroll-snap-type: x mandatory strip with hand-made arrows and dots Carousel and CarouselItem: slides inert off-screen, labelled “n of m”, dots, opt-in autoplay with Pause Carousel
A custom “nothing here” paragraph EmptyState, or the empty snippet of AppList EmptyState
A hand-made loading flash or a spinner that blinks on fast loads LoadingBoundary for a route or section, Skeleton for content shape LoadingBoundary
Your own copy-to-clipboard button CopyButton: swaps to a check, announces the result CopyButton
Adjacent Buttons with border-radius: 0 and a margin-left: -1px on the siblings ButtonGroup: attached buttons with a single-line seam, role="group", orientation ButtonGroup
A div with a border around a bare <input>, a $ span and a button, with :focus-within styles TextField prefix / suffix (string for text, snippet for a button) TextField
Your own toast stack or aria-live region toast.success() with one Toaster, or announce() for speech only Toast
A .overdue pill class with color-mix, a 6px .dot span and a fixed height <Badge tone="danger" subtle dot size="md">Overdue</Badge> Badge
@media (max-width: 767px) { .ca-btn__trailing { display: none } } to hide a Kbd hint <Button trailingHint> with the Kbd in trailing Button
justify-content: flex-start and margin-left: auto on .ca-btn__trailing <Button align="between" fullWidth> Button
100vh or 100dvh height: var(--ca-vh) Mobile
cursor: pointer on a clickable div role="button", summary or label for, or cursor: not-allowed on a disabled one Nothing: the reset layer (@layer ca.reset) already sets pointer on button, a[href], label[for], summary and [role=button|tab|option|menuitem*], and not-allowed on :disabled and [aria-disabled=true]. An unlayered app rule such as .tile { cursor: grab } overrides it with no !important Theming
line-height: 1.7 (or any unitless value) on a code font, or a highlight layer whose line height does not equal the text layer’s, so a caret and an active-line band drift apart line-height: var(--ca-code-line-height) (integer px) and font-family: var(--ca-font-mono) on every layer of the code surface CodeSnippet
An edge peek, rail flyout or hover panel that opens while a dialog is open, or a document.querySelector('dialog[open]') check before opening it layers.modalOpen (reactive) or layers.blocks(trigger). Tooltip, HoverCard and NavigationMenu already stay shut under a modal Dialog
A min-height: 44px touch override Nothing: controls grow to 44px under (pointer: coarse) Mobile
padding-bottom: env(safe-area-inset-bottom) on fixed UI var(--ca-safe-bottom) and the other --ca-safe-* tokens Mobile
A keyboard-padding hack for a form or composer use:keyboardAware Mobile, @codeatlasdev/ui/actions
Local dark mode state, a class toggle on <html> ThemeToggle and the colorScheme store ThemeToggle, Theming
A wrapper that forces a dark or light island data-theme-scope="dark" or "light" on the element Theming
Inline padding, margin or gap in pixels Flex, Stack, Grid and Box props (gap="4"), or var(--ca-space-N) in a class Layout primitives
A raw hex, rgb() or oklch() color A --ca-* token Theming
Table rows rebuilt as cards on a phone SimpleTable responsive="cards"; add data-label on a td only to change its caption SimpleTable
A toolbar div with flex: 1 spacers Flex, the toolbar snippet of AppList, or the ca-toolbar-spacer class AppList
Visually hidden text with display: none or clip rules The ca-sr-only class Accessibility
useState, useEffect, useMemo ported line by line $state, $derived, $effect Migrate from React
html { font-size: 16px } to stop --ca-font-size-body1 rescaling every rem Obsolete: body text no longer follows the root rem. Override --ca-font-size-body1 only; the root rem stays 15px Typography
A StatusChip, Chip or Badge moved out of PageShell actions so it does not stretch Keep it in actions: it keeps its natural width. Only Button goes full-width on a phone PageShell
A map or canvas mounted by hand behind the shell, or remounted on every route AppShellLayout stage snippet; stageVisible={false} hides it on a full-page route without unmounting AppShell
Hand-rolled maplibre or mapbox plus deck.gl glue with a theme-following style MapStage, MapControls and useMapTheme from @codeatlasdev/ui/map; PageFrame for the floating panel or bottom sheet, which reports the covered area on stageInsets Map, PageFrame
A search or ⌘K button positioned over the rail; an own “More” tab for more than 5 mobile modules; captions under rail icons AppShellLayout: railTop snippet; bottomNavPrimary with bottomNavOverflow and moreSheet={NavMoreSheet}; railLabels AppShell
An own show/hide password button, or a “Forgot password?” link under the field TextField type="password" revealable; the below snippet for the link TextField
An own language picker LocaleSwitcher: options, value, onselect, compact; put it in the trailing snippet of SiteHeader LocaleSwitcher
A page wrapper that forces another preset or scheme (a light landing in a dark app) ThemeIsland preset scheme, plus document for a full page and setRouteTheme from @codeatlasdev/ui/kit on the server ThemeIsland
A per-preset CSS override of the primary button or the input font size colors.dark.brandFill, brandFillHover, brandContrast and sizes.inputFontSize in the theme Theming
Own chip radio buttons for a single choice ChipGroup: bind:value, items, label, error ChipGroup
Own toast de-duplication or cap, or a second line or undo button in a toast toast with id replaces in place; description, action: { label, onClick }. Identical messages already dedupe (count) and 3 show at most Toast
An outlined or ghost Button restyled neutral with local CSS tone="neutral" on Button (outlined, ghost) and IconButton Button
A thinner Progress by overriding the track CSS Progress size="sm" or "md", or --ca-progress-height for another height Progress
A card-less metric built from KpiCard with the border removed Stat: label, value, unit, hint, trend, trendTone, size, align Stat
trend dropped and the delta written in hint because down is good (churn, cost, latency) trendTone="positive-down" on Stat and KpiCard; "neutral" to not judge the change Stat, KpiCard
Spreadsheet-like rows, a hand-pinned first column, group rows SimpleTable density="compact", stickyColumns, TableGroupRow, TableRow onactivate SimpleTable
An own board with drag between columns Kanban: columns, getId, onmove, onloadmore Kanban
A side detail panel built by stripping the header and padding from a Drawer Drawer chromeless (plus fullBleedBelow for a full-screen phone view) Drawer
A Card title header that is misaligned, or an own stack inside a card Card title is aligned with the content; Card gap stacks the children Card
A headline font set with local CSS; hand-written highlight or strike-through CSS Heading size="display" or the display prop (PageShell, AuthCard, SiteHeader, EmptyState), --ca-font-display; Highlight, StrikeThrough (animated) Heading, Highlight, StrikeThrough
GlassCard, GlassSurface, Row, Grid cols=, gap={16} Card, Surface, Flex, Grid columns=, gap="4". Run bunx @codeatlasdev/ui migrate --write Choosing a component
A domain.css of --app-status-*, --app-tier-* or --app-channel-* colors tokens: { status: { new: { light, dark } } } on the preset: --ca-token-status-new (+ -subtle, -contrast) follows the scheme and the preset Domain tokens
A 1x1 <canvas> that resolves getComputedStyle(root).getPropertyValue(token) to [r, g, b, a] tokenRgba("status.new") or tokenRgba("--ca-brand-main") Domain tokens, @codeatlasdev/ui/tokens
A hex computed by hand to flatten a translucent text or border color onto one background The CSS color as written: textSecondary: "oklch(1 0 0 / 0.62)" or borderSubtle: { color: "#fff", alpha: 0.1 }. The build checks text contrast after compositing Porting a palette by role
A parallel --app-text-* scale or .app-label classes of font-size, line-height and letter-spacing The type roles: <Text role="label">, .ca-text-label, font: var(--ca-text-label); restyle them once with type in the theme Type roles
font-variant-numeric: tabular-nums and a weight on every counter or clock <Text role="num"> or .ca-text-num Type roles

Still stuck

If nothing above fits, it may be a real gap in the library.

  1. Look the prop or component up: get_component for a name, search_demos for a task. A demo often shows the combination you need.
  2. If it is not there, write the smallest workaround and mark it with the issue number: // ca-ui-workaround(#<issue>): <why>. In markup use <!-- ca-ui-workaround(#<issue>): <why> -->.
  3. Call report_issue to draft the sanitized issue, and open it.

Details and what never goes into a report: Reporting problems.