# Alpha > Alpha is the Growth Protocol design system: a React component package > (`@growth-protocol-ai/alpha`, v0.11.1) styled with CSS Modules over unprefixed CSS > custom properties. Surface documents are generated from the package registry; > cross-cutting documents are checked against the emitted package. Together they > describe the version you have installed and nothing else. Read `llms/adopting.md` before replacing an existing component with an Alpha one — it states Alpha's boundaries and the checks a substitution needs. Import components from the package root and icons from the `/icons` subpath. The only supported selector into a component is `[data-slot]`. Alpha ships no layout or typography primitives and no spacing scale; that code stays in your application. ## Contract - [Building with Alpha](llms/building.md): selecting, composing and validating Alpha surfaces for new UI - [Adopting Alpha](llms/adopting.md): the boundaries, the substitution procedure, and what to do when Alpha has no equivalent - [Setting up Alpha](llms/setup.md): installation, the one stylesheet import, mode, fonts and removal boundaries - [Rules block](llms/rules.md): paste-ready instructions for a consuming repository's AGENTS.md, CLAUDE.md or .cursor/rules - [Selectors and overrides](llms/slots.md): how to restyle a component from outside it, and the portalling caveat that catches everyone - [Entry points](llms/entry-points.md): the whole public surface, subpath by subpath ## Components - [Accordion](llms/accordion.md): Accordions are stacked rows that each hide a panel of content until the reader opens it. - [Button](llms/button.md): Buttons are the controls a reader presses to make something happen. - [Card](llms/card.md): Cards are self-contained surfaces that each carry one unit of information. - [Checkbox](llms/checkbox.md): Checkboxes let a reader choose any number of options from a list, including none of them. - [Dropdown](llms/dropdown.md): Dropdowns let a reader pick one value from a list that stays out of the way until it is needed, or several when it is set up for that. - [EmptyState](llms/empty-state.md): Empty states explain why a place that would normally hold content is empty, and what the reader can do about it. - [Markdown](llms/markdown.md): Markdown renders a string of markdown as formatted text — headings, lists, tables, links and fenced code — styled to match the rest of the interface. - [Modal](llms/modal.md): Modals are dialogs that open over the page and hold the reader’s attention until they are dealt with. - [Pagination](llms/pagination.md): Pagination lets a reader move through a long list one page at a time. - [Popover](llms/popover.md): Popovers are small panels anchored to the control that opens them, holding content or controls the page has no room to keep on show. - [Radio](llms/radio.md): Radios let a reader pick exactly one option from a group. - [Search](llms/search.md): Search is the field a reader types a question into. - [Skeleton](llms/skeleton.md): Skeletons stand in for content that has not arrived yet, drawn in roughly the shape it will take. - [Spinner](llms/spinner.md): Spinners say that something is in progress without saying how far along it is. - [Tabs](llms/tabs.md): Tabs are a row of labels that switch a surface between alternative views of itself, one at a time, without leaving the page. - [Tag](llms/tag.md): Tags are small inline labels that mark or categorise whatever they sit beside. - [TextArea](llms/text-area.md): Text areas collect several lines of typed text. - [TextInput](llms/text-input.md): Text inputs collect a single line of typed text. - [Toggle](llms/toggle.md): Toggles are switches for a setting that takes effect the moment it is flipped. - [Tooltip](llms/tooltip.md): Tooltips are short hints anchored to a control, shown when the reader hovers over it or moves focus to it. ## Modules - [Canvas](llms/canvas.md): The canvas is the surface an assembled layout is read and edited on. - [ConfirmationModal](llms/confirmation-modal.md): The confirmation modal asks the reader to confirm one action before it happens. - [ErrorView](llms/error-view.md): The error view tells a reader that something has failed and what that means for them. ## Foundations - [Colour, typography and tokens](llms/tokens.md): semantic roles, mode-aware theming, type scales, layout boundaries and every token name - [Icons](llms/icons.md): Icons are the glyph set Alpha publishes, for use inside its own components and in your markup. ## Optional - [llms-full.txt](llms-full.txt): every document above, inline --- # Setting up Alpha Use the package already installed in the application. Its local `dist/llms.txt` describes that exact version; documentation from another checkout or a newer website can describe props the application does not have. If Alpha is not installed, add it only when the task authorises a dependency change. Keep registry credentials outside the repository: Alpha is published through the internal Google Artifact Registry and authenticated with a short-lived Google identity token, which must never appear in a configuration file that will be committed. ## Styles and mode Import the complete stylesheet once at the application root: ```tsx import '@growth-protocol-ai/alpha/styles.css'; ``` Set `data-mode="dark"` or `data-mode="light"` on ``. Dark is the `:root` default, but declaring the mode makes the application's intent explicit and gives a theme switch one attribute to change. A switch sets that attribute and persists the choice; apply the stored value before paint so the first render is not the theme the reader turned off. Do not add a theme provider or re-render the tree for it — the custom properties are inherited. The selector is not anchored to ``, so the same attribute on any element themes that subtree, and a nested value wins over the one above it. Do not add a reset or a provider for Alpha. Components normalise their own roots, and theming is CSS custom properties rather than React context. Keep an existing provider until its last non-Alpha consumer is gone; removing it early can change parts of the application that were not in the migration. ## Fonts Alpha names its font stacks but ships no font files. Keep the application's existing font loader and point `--font-lato` or `--font-nwo` at the family it loads. A token containing a family name does not download that typeface. ## Imports Components and modules come from `@growth-protocol-ai/alpha`. Icons come from `@growth-protocol-ai/alpha/icons`, one static named import per drawing. The package has no default export, theme provider, reset component or dynamic icon lookup. --- # Building with Alpha Read this when creating new UI rather than replacing an existing implementation. If Alpha is not integrated yet, read `setup.md` first. Then use `llms.txt` to load only the foundation and surface documents the work needs. Alpha supplies components, modules, icons and visual foundations. It does not decide the application's routes, data flow, page structure or layout. Keep that boundary visible while planning the UI: Alpha owns the contract inside a published surface; the application owns how those surfaces are arranged and what happens around them. ## Start with the job, not a component name Before choosing a surface, state what the reader needs to do or understand: - the semantic role and expected element; - the content and accessible name; - the available, disabled, pending, empty, error and success states that apply; - who owns the state and whether it is controlled; - the event the application needs and the value it must receive; - focus, keyboard and dismissal behaviour; - the surrounding layout and what changes at narrow widths. Search `llms.txt` for surfaces that provide that capability. Read each candidate's "When to use", "When not to use", props, states and guidelines before selecting it. A familiar name is not evidence that the component does the required job. Where a generated document and the emitted declaration ever disagree, the `.d.ts` is the contract. ## Choose the ownership boundary Use the smallest boundary that expresses the design without hiding behaviour: 1. **Use a published Alpha component** when its semantics, state and events match the requirement. 2. **Use a published Alpha module** only when the fixed arrangement itself is the requirement. Do not choose a module merely to save a few lines of composition. 3. **Compose Alpha surfaces in application markup** when the arrangement is specific to the feature. Forms, toolbars and page sections usually belong here. 4. **Use semantic HTML or an application-owned component** when `llms.txt` contains no matching surface. Do not construct an imitation from unrelated Alpha components, import an internal path or invent props that sound likely. An application-owned component is useful when several call sites share feature behaviour or layout. Keep its API in the language of the application and use Alpha inside it where the capabilities match; do not expose Alpha's entire prop surface by default. ## Build the composition 1. Import components from `@growth-protocol-ai/alpha` and icons from `@growth-protocol-ai/alpha/icons`. Import no path below `dist/`. 2. Start with the documented basic usage. Add a prop because the requirement calls for it, not to make every default explicit. 3. Put content in the documented place. A label may be children, a `label` prop, or external markup associated with a void element; these shapes are not interchangeable. 4. Decide state ownership deliberately. Do not pass a controlled prop without updating it from the corresponding event, and do not add local state when a form or feature controller already owns the value. 5. Match handler arguments exactly. A DOM event, a selected value and a no-argument action are different contracts even when the handlers share a familiar name. 6. Treat pending and disabled as behaviour, not decoration. Prevent duplicate actions, preserve the accessible state and keep the label meaningful while work is in progress. 7. Use one static icon import per glyph. Pass an icon element to an icon slot, let the surrounding component size and colour it, and label the control rather than the decorative glyph. ## Keep layout in the application Alpha has no layout or typography primitives and no spacing or breakpoint scale. Use semantic elements and the application's stylesheet for grids, stacks, page widths, responsive changes and running text. Do not search for an Alpha `Box`, `Stack`, `Grid` or `Typography`, and do not turn a component into a layout primitive by pushing appearance rules through `className`. Use this styling order: 1. Override a documented token when the product's visual foundation changes. 2. Put layout-only rules such as width, flex placement and margin on a root `className`. 3. Use a documented `[data-slot="..."]` or `[data-module="..."]` selector for a contextual rule that must reach a published part. Read `slots.md` before styling an overlay because portalled content is not a DOM descendant of its trigger. Never target Alpha's generated class names, recreate a variant's geometry, or pass an `sx` prop or style object. If the desired appearance requires changing the component's private structure, the requested design is outside the published contract and needs a design decision rather than a CSS workaround. ## Accessibility is part of the selection - Prefer the native element whose meaning matches the action or content. - Give every control an accessible name. Associate fields with visible labels, and use `aria-label` for a control that intentionally contains only an icon. - Preserve the keyboard and focus behaviour documented for compound and overlay surfaces. Do not put an interactive element inside another one. - Connect help, validation and status text through the semantics the feature needs; proximity and colour alone do not create a relationship. - Exercise focus movement, dismissal, keyboard activation and announced state directly. A typecheck cannot verify them. ## Track work that spans files Use the consuming repository's existing issue or implementation-plan format. If it has none and the work will span sessions, keep a short `alpha-ui-plan.md` with one row per feature area: required capability, chosen Alpha surface or `none`, state owner, status and validation. Update it with each batch so remaining states and accessibility checks are not held only in conversation memory. The plan is discovery state, not permission to broaden the feature. Mark a surface complete only after its behaviour is exercised, and record why an application-owned implementation was chosen when Alpha has no match. ## Validate the finished UI Run the application's own typecheck, lint and tests, then use its visual harness where one exists. Check every relevant state in both modes and at the layout's responsive boundaries. Exercise events, controlled state, focus, keyboard behaviour and overlays rather than treating a clean render as proof. Finally, search for internal Alpha paths, generated class selectors, unsupported props and duplicated stylesheet imports. The UI is complete when the required behaviour is present through public contracts—not merely when every visible piece carries an Alpha import. --- # Adopting Alpha Read this before replacing an existing component with an Alpha one, whatever it is being replaced with — a third-party library, an in-house component folder, or markup written by hand. Alpha does not know how your application is built, so this document states Alpha's own boundaries and the checks a substitution needs. It never guesses at an equivalence, and neither should you. ## Alpha publishes exactly what `llms.txt` lists That index is generated from the package's own registry at build time, so it is complete for the version you have installed. A component that is not in it is not Alpha's, and no amount of prop-guessing will make it exist. ## What Alpha does not ship The rule is total and never goes stale: **Alpha exports exactly the surfaces `llms.txt` lists.** If what you need is not one of them, Alpha does not ship it — leave the existing implementation in place, mark it, and do not approximate it out of other Alpha components. The ones below are called out because they are the ones most often reached for, not because the list is complete. It cannot be: the set of things Alpha does not export is unbounded. - **No layout or typography primitives.** There is no `Box`, `Stack`, `Flex`, `Grid`, `Typography` or `Text`. Layout and running text belong to the application, in its own stylesheets. Leave them alone. - **No spacing scale and no breakpoint scale.** Alpha's tokens cover colour, radius, elevation, type and one motion curve. Control heights live inside the components. Spacing between things is yours. - **No style escape hatch.** There is no `sx`, no style-object prop and no `styled()`. See "The style path" below for what to do instead. - **No theme provider and no reset.** Theming is a CSS custom property override plus `data-mode` on ``; there is no React context to wrap anything in. Alpha emits no element selectors, so removing a reset from your app changes your app, not Alpha. - **No table, data grid or menu.** A `Dropdown` is a value picker and a `Popover` is a panel holding whatever you put in it; neither is a menu of commands carrying its own keyboard contract, and neither is a table. - **No dynamic icon lookup.** There is no name-keyed map from string to glyph, because that map is exactly what would stop a bundler dropping the glyphs an application does not use. ## The substitution procedure 1. **Inventory the application before changing it.** Search imports, re-exports, path aliases, JSX, local component directories, theme providers and styling APIs. Follow each candidate to the module that implements it. The source may be a package, a wrapper around one, or markup written directly in the app; its import graph, not its folder name, tells you which it is. 2. **Identify the source component by its import, and read it.** One name is routinely several components: a `Tooltip` from a third-party library, a `Tooltip` in the application's own component folder, and a wrapper around the first that exists only to show a hint when text overflows are three different things with three different answers — and the third has no Alpha equivalent at all. Resolve the import specifier, open the implementation, and decide per specifier, never per name. 3. **Choose the migration seam.** When an application-owned wrapper can keep the API its callers use while rendering Alpha inside, change that wrapper and validate its callers as one contract. When preserving the wrapper would hide a behavioural mismatch or keep source-specific props alive, migrate the affected call sites instead. Do not bypass an application abstraction merely to make the Alpha import visible at every use. 4. **Match on capability, not on name.** A tooltip is a tooltip whichever library drew it. A component that shares a name with an Alpha one but does something else — a "Dropdown" that is really a positioned panel, a "Card" that is really a layout grid — is not a match, and a rename would be a regression dressed as a migration. 5. **Read that surface's own document** — `llms.txt` lists one per surface — before writing a line of it. Every prop, every accepted value and every default is there. Where that table and the package's emitted `.d.ts` ever disagree, the `.d.ts` is the contract. 6. **Check the shape hazards.** This is where a mechanical rename compiles and then misbehaves, so check every one of these each time: - **A prop Alpha does not own becomes a DOM attribute.** Alpha components spread the native props of the element they render, so an unrecognised prop is not an error — it lands on the element. The costly case is a name that collides with a real HTML attribute: if the source component used `type` for its visual variant, then `type="primary"` on an Alpha button is a valid React prop, renders no variant, and gives the element an invalid `type` — which a browser treats as `submit`, so the button now submits the form it sits in. Rename by attribute name, never by value, and include the computed ones (`type={x ? 'a' : 'b'}`). - **A value outside a closed union fails silently.** The variant tables are exhaustive, and a value that is not in one produces no class: the component renders unstyled, with the attribute set to your bad value. In TypeScript that is a compile error. In plain JavaScript nothing tells you. - **The handler's name and its argument.** A field that called `onChange(nextValue)` with a bare string does not survive being pointed at a handler that receives a DOM event, and nothing will tell you: the code compiles and the value arrives as `[object Object]` or `undefined`. - **Controlled versus uncontrolled.** An explicitly passed `false` is a controlled closed component, which is not the same thing as an uncontrolled one that happens to be closed. - **Defaults differ, so dropping a prop is not a no-op.** Omitting a prop takes Alpha's default, which is rarely the source's — a size that was implicit before can come out visibly smaller. Spell out what the old default gave you rather than letting both defaults apply. - **Two source booleans may be one Alpha axis.** Where the source expressed something with independent flags and Alpha expresses it as a single union, some combinations are not expressible at all. The source resolved them by CSS rule order; Alpha makes you choose, and that choice is a decision to record rather than to guess. - **Where the content goes.** Whether the label is the children, a prop, or nothing at all because the element is void. 7. **Geometry is Alpha's.** Sizes are fixed axes with named values, and there is nothing between them or below the smallest. If the surrounding layout cannot absorb the size Alpha offers, that is a design decision for a person to take — adjust the container, or leave the existing control in place. Re-specifying a height through CSS is re-implementing the axis Alpha deliberately withheld. 8. **Take the style path.** In order of preference: - **A token override** for anything about appearance. Alpha's custom properties are unprefixed, so they are ordinary globals — if your application already declares one of these names, one of you will lose. Override in the same two-block shape the package uses, or a bare `:root` rule will land on both modes at once. - **`className` on a component root, for layout only** — width, flex, grid position, margin. Never for appearance. - **`[data-slot="…"]`** for a contextual override that belongs to one place in your layout. See `slots.md`: it is the only selector into a component that Alpha supports, and overlays are portalled, which defeats the descendant selector everyone reaches for first. - **Never** the hashed class names. They are content-addressed and change between builds. 9. **Icons are one static import per glyph**, by name, from the `/icons` subpath. If no Alpha glyph matches the drawing you are replacing, keep the existing icon — an approximate glyph is a silent visual change. Sizes are the named steps only, never a number, and an icon is never a control: the handler and the accessible name belong to the thing around it. 10. **Leave what you cannot resolve, and say so.** Where the mapping is genuinely ambiguous — a size with no counterpart, a prop with no equivalent, a layout that would have to change — do not pick the closest thing. Leave the existing code in place and mark it: ``` // TODO(alpha): ``` A file that migrates eight of ten call sites and flags two is a good result. A file that migrates ten by guessing at two is a bad one, and the guesses are the expensive part to find later. ## Keep a migration ledger For work that spans files or sessions, create `alpha-migration.md` in the consuming application's root and update it as part of every batch. Use one row per resolved source export or application-owned wrapper, not one row per name: | Source | Resolved implementation | Call sites | Capability | Alpha target | Status | Blocker | Validation | | ------------------ | ----------------------- | --------------- | ------------ | ----------------- | ------------------------------------------------------ | ----------------- | ---------- | | `specifier#export` | `path` | paths or search | what it does | surface or `none` | `unreviewed`, `ready`, `migrated`, `blocked` or `keep` | decision required | checks run | The ledger is discovery state, not permission to broaden the migration. Add newly found call sites before editing them, record why an item stays, and mark a row migrated only after its validation passes. A source dependency, provider, reset or stylesheet can be removed only when searches show no remaining code or configuration that needs it. ## Validate in batches Use the consuming application's own gates: typecheck, lint, tests and its visual harness where one exists. Also search for the source import and wrapper after each batch. TypeScript cannot prove that focus returns to the trigger, that an event still carries the same value, that a portal is styled in its new location, or that a default size did not change; exercise those behaviours directly. --- ## Alpha design system (`@growth-protocol-ai/alpha`) This project uses Alpha. - **The installed package documents itself.** Read `node_modules/@growth-protocol-ai/alpha/dist/llms.txt` — it indexes one document per published surface and the cross-cutting foundation documents, generated and checked with the package, so it describes the version this project has installed. Read `node_modules/@growth-protocol-ai/alpha/dist/llms/building.md` before creating new UI, `node_modules/@growth-protocol-ai/alpha/dist/llms/adopting.md` before replacing existing UI and `node_modules/@growth-protocol-ai/alpha/dist/llms/setup.md` before changing application-level setup. - **For new UI, start with the required capability and semantics.** Read the building guide and the candidate surface documents before choosing a component. If Alpha has no match, use semantic HTML or an application-owned component rather than inventing an Alpha API or approximating the design with an unrelated surface. - **Discover before replacing.** Resolve imports, re-exports, aliases and local wrappers, then read the implementation and its call sites. Match an Alpha surface by capability and behaviour, never by a shared name or by which library the source came from. - **Prefer the narrowest safe seam.** If a local wrapper can keep its public contract while using Alpha inside, migrate the wrapper once. If its callers depend on behaviour Alpha cannot preserve there, migrate those callers individually and leave the wrapper in place for the rest. - **Preserve semantics and state.** Check the rendered element, accessible name, focus and keyboard behaviour, event arguments, controlled and uncontrolled state, defaults, disabled and pending behaviour, content placement, layout and visual intent. A compiling rename is not proof of equivalence. - **Track a migration that spans files.** Create or update the ledger described in the adoption document; do not rely on conversation memory for remaining call sites, blockers or validation. - **Import components from the package root**: `import { Button } from '@growth-protocol-ai/alpha'`. - **Import icons from the `/icons` subpath**, by name, one static import per glyph: `import { SearchIcon } from '@growth-protocol-ai/alpha/icons'`. There are no icons on the package root and there is no name-based `` — the static import per glyph is what lets a bundler drop the rest. - **An icon slot takes the element, not the component**: ` ``` ## When to use Reach for a button when the reader is doing something rather than going somewhere: submitting, saving, deleting, opening a dialog. Give each action group one primary button and let the rest of the group take a lower emphasis, so a reader can see at a glance which action the screen is recommending. ## When not to use Do not use a button to move the reader to another page — that is a link, and a link is what gives them a middle-click, a new tab and a preview of the destination. A control that holds a value rather than firing once is not a button either; reach for Toggle, Checkbox or Dropdown. ## Props | Name | Type | Default | Notes | | --- | --- | --- | --- | | `variant` | `"primary" \| "secondary" \| "outlined" \| "danger"` | `"primary"` | What the action is worth. See the variant table above. | | `emphasis` | `"depth" \| "solidFlat" \| "ghost"` | `"solidFlat"` | How much room it gets to say it. Independent of variant. | | `size` | `"regular" \| "large"` | `"regular"` | 36px or 52px. Geometry only — never changes intent. | | `rounding` | `"default" \| "full"` | `"default"` | 12px, or a pill. | | `iconLeft` | `ReactNode` | — | Glyph before the label. Sized to 20px, and the padding on that side tightens to balance it. | | `iconRight` | `ReactNode` | — | Glyph after the label. Same sizing and padding rule as iconLeft. | | `iconOnly` | `boolean` | `false` | Square button — 36px or 52px — whose children are the glyph. Pair it with an aria-label. | | `disabled` | `boolean` | `false` | Non-interactive, and repainted rather than faded. Also set by loading. | | `loading` | `boolean` | `false` | Shows a spinner, sets aria-busy and blocks interaction. | | `asChild` | `boolean` | `false` | Render the child element instead of a