Controls come from components/ui.
AGENTS.md says how to use and extend them.
Don't style a raw <button>, <input>, <select>, or <textarea> to look like a control a
primitive provides. Raw elements are right when the element isn't that control: semantic rows, tabs,
resize handles, swatches, editor surfaces, anything whose behavior or geometry differs by design.
Style with Tailwind classes in the component that renders the element.
index.css or any other stylesheet, is only for
what classes on the owning component can't express: generated Markdown or imperative DOM, custom
elements and shadow roots, animations, runtime theme variables, and browser or Electron
integration.style={{ ... }} or inline <style> for static values a class covers. Values computed at
runtime are fine.@variant dark and @variant light, not .dark selectors.The composer banners are the reference.
ComposerBanner.tsx exports one object
of small slots. Slots own their classes, take className, and spread the rest of their props,
merging classes with cn. Variants and density are props on Root. A slot that needs a control
renders Button.ComposerBannerStack.tsx composes
the slots and owns only stack behavior: priority, expand and collapse, dismiss transitions.ComposerActivityStatus.tsx.Build new UI the same way. Compose or extend a component instead of copying its markup and classes.
When a call site repeats a treatment another one already uses, make it a variant or a slot on the
shared component. A new composer banner or notice uses the ComposerBanner slots.