---
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.