| 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
"use client";
import { useState } from "react";
import { Button, Input, Card } from "@stellar/design-system";
import "./styles.scss";
interface ComponentNameProps {
propName: string;
}
export const ComponentName = ({ propName }: ComponentNameProps) => {
return (
<div className="ComponentName">
<div className="ComponentName__header">
{/* ... */}
</div>
<div className="ComponentName__content">
{/* ... */}
</div>
</div>
);
};
SCSS Template
.ComponentName {
&__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:
<div
className="TransactionStepper__step"
data-is-active={isActive || undefined}
data-is-completed={isCompleted || undefined}
data-is-clickable={isClickable || undefined}
onClick={isClickable ? () => onStepClick(step) : undefined}
>
.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.