web/src/components/design-system/README.md
This folder contains reusable, primitive, presentational UI components.
Do not include:
TracePanel)design-system/
Button/
Button.tsx
Button.stories.tsx
No className or style props
No arbitrary values (e.g. #fff, 12px)
Use explicit enums:
size: "sm" | "md" | "lg";
variant: "primary" | "secondary";
Use cva for all variants
Use explicit enums (no free-form values)
Prop values must never match Tailwind class names:
size="md"size="w-5 h-5"Enforce mutually exclusive props at type level
Use positive naming:
suffix={null}noSuffixBoolean props must use is / should:
isLoading, shouldTruncateDesign-system components own visual states, not business logic.
Logic-heavy components must reuse design-system components for visuals instead of recreating UI internally.
// ✅ Button owns the loading visual state
type ButtonProps = {
isLoading: boolean;
};
const PromiseButton = (props: PromiseButtonProps) => {
const [isLoading, setIsLoading] = useState(false);
return <Button isLoading={isLoading} />;
};
// ❌ PromiseButton reimplements Button loading visuals
const PromiseButton = (props: PromiseButtonProps) => {
const [isLoading, setIsLoading] = useState(false);
if (isLoading) {
return (
<div>
<Spinner />
</div>
);
}
return <Button isLoading={isLoading} />;
};
className / stylecvais / shouldIf unsure: only include reusable, design-only primitives.