--- name: component-guide description: Guide for building React components using @stellar/design-system and project SCSS conventions. Invoke when creating new components or reviewing component code. read_files: - .claude/skills/component-guide/reference/*.md --- # Component Guide ## Before Building Anything Custom Check if `@stellar/design-system` already has the component: https://github.com/stellar/stellar-design-system > For the full component catalog (SDS + local layout wrappers) and props > patterns, see `reference/ui-components.md` (loaded automatically). ## Component File Structure ### With styles (preferred for non-trivial components) ``` src/components/ComponentName/ ├── index.tsx └── styles.scss ``` ### Without styles (simple components) ``` src/components/ComponentName.tsx ``` ### Page-specific components ``` src/app/(sidebar)/[feature]/components/ComponentName.tsx ``` ## Component Template ```typescript "use client"; import { useState } from "react"; import { Button, Input, Card } from "@stellar/design-system"; import "./styles.scss"; interface ComponentNameProps { /** Description of prop */ propName: string; } /** * Brief description of what this component does * * @example * */ export const ComponentName = ({ propName }: ComponentNameProps) => { return (
{/* ... */}
{/* ... */}
); }; ``` ## SCSS Template ```scss .ComponentName { // Root styles &__header { display: flex; align-items: center; justify-content: space-between; } &__content { display: flex; flex-direction: column; gap: pxToRem(16px); } &__footer { display: flex; gap: pxToRem(8px); } } ``` ## Conventions ### Do - Use design system components for all standard UI elements - Use SCSS with BEM-ish class naming (`ComponentName__element--modifier`) - Use `pxToRem()` for spacing values in SCSS (skip for trivial values like `1px` or `-1px` — e.g., borders, outlines, offsets — where rem scaling is not meaningful) - Use SDS CSS custom properties for colors/fonts/gaps: `var(--sds-clr-gray-06)`, `var(--sds-ff-monospace)`, `var(--sds-gap-md)` - Use `data-*` attributes for state-driven styling instead of modifier classes: `data-is-active`, `data-is-visible`, `data-is-selected`, `data-is-clickable` - Use `data-testid` with dashes for test selectors (`data-testid="sign-button"`) - Add JSDoc comments with `@example` for exported components - Co-locate page-specific components with their page - Import shared SCSS utilities: `@use "../../styles/utils.scss" as *;` ### Don't - Use inline `style={}` attributes — always use SCSS classes - Create custom buttons, inputs, or alerts when design system has equivalents - Use arbitrary hex colors — use SDS CSS custom properties (`--sds-clr-*`) - Put styles in the component file — always separate into `.scss` - Use `className` string concatenation — use template literals or classnames lib - Use conditional CSS classes for state — prefer `data-*` attributes ## Data Attribute Pattern for State-Driven Styling Prefer `data-*` attributes over CSS modifier classes for dynamic state: ```typescript // Component
onStepClick(step) : undefined} > ``` ```scss // SCSS — target with attribute selectors .TransactionStepper__step { opacity: 0.5; &[data-is-active="true"] { opacity: 1; font-weight: var(--sds-fw-medium); } &[data-is-clickable="true"] { cursor: pointer; } &[data-is-completed="true"] { opacity: 0.8; } } ``` Pass `undefined` (not `false`) to omit the attribute from the DOM entirely.