agentsclimarketplace

React style guide

Skill r-portas/skills/react-style-guide

Roy's React conventions for shadcn/ui and Tailwind — component and file naming, props typing, region blocks, `cn()` class composition, conditional JSX, and TSDoc. Consult whenever writing, editing, or reviewing React components or JSX.From its SKILL.md

Install
npx -y skills add r-portas/skills --skill react-style-guide

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

4.5 KB, 947 tokens by cl100k_base, as published. Nobody here has run it

React Style Guide

For general TypeScript conventions (interface vs type, file naming, region blocks, TSDoc for utilities), see the typescript-style-guide skill.

Components

Naming and file conventions

File names use lowercase with hyphens: search-input.tsx, page-header.tsx. Component functions use PascalCase: SearchInput, PageHeader. These always match — a file named page-header.tsx exports PageHeader.

The main component in a file uses a default export. Sub-components and everything else use named exports.

Component location

See tanstack-start-project-structure for the full directory layout.

Props typing

Props and data shapes both use interface — see typescript-style-guide for when to reach for type instead.

interface PageHeaderProps {
  title: React.ReactNode;
  lead?: React.ReactNode;
  actions?: React.ReactNode;
}

interface PostSummary {
  slug: string;
  title: string;
  date: string;
  tags: string[];
}

Component splitting

Extract a component when it manages its own state, has its own loading/error state, or can be described independently. Keep things inline otherwise — prefer fewer files.

If an extracted component is only used in one place, keep it in the same file as the parent rather than creating a new file.

File structure

Only add regions when a file has more than one logical part. A file with a single component needs no regions at all. When a file has multiple parts, follow the region ordering from typescript-style-guide: co-locate types and helpers with the region that uses them.

// post-card.tsx

// #region PostCard
interface PostCardProps {
  /** The post data to display. */
  post: PostSummary;
  /** Extra Tailwind classes forwarded to the root element. */
  className?: string;
}

export default function PostCard({ post, className }: PostCardProps) {
  return <article className={cn("rounded-lg", className)}>...</article>;
}
// #endregion

// #region PostCardMeta
interface PostCardMetaProps {
  date: string;
  tags: string[];
}

function PostCardMeta({ date, tags }: PostCardMetaProps) {
  return <footer>...</footer>;
}
// #endregion

Classnames

Use cn() (from @/lib/utils) to compose Tailwind classes. Don't use string interpolation or manual ternaries for class composition. Always accept and forward a className prop on presentational components so callers can extend styles.

JSX style

For conditional rendering, prefer logical AND for optional slots, ternary for binary states, and early return for guards.

// Optional slot — logical AND
{lead && <Lead>{lead}</Lead>}

// Binary state — ternary
{isLoading ? <Spinner /> : <Content />}

// Guard — early return
if (posts.length === 0) return null;

Documentation

Default exported components get a TSDoc comment. Each prop gets an inline comment. One sentence is enough. Prop comments can be brief phrases; omit only when the prop name is completely self-explanatory.

/**
 * Displays a post summary card with title, date, and tag list.
 */
export default function PostCard({ post, className }: PostCardProps) {
  return <article className={cn("rounded-lg", className)}>...</article>;
}

interface PostCardProps {
  /** The post data to display. */
  post: PostSummary;
  /** Extra Tailwind classes forwarded to the root element. */
  className?: string;
}

Event handlers

Name handlers handle + action: handleCopy, handleSubmit, handleSelect. For simple inline handlers, inline is fine.

<button onClick={handleCopy}>Copy</button>
<button onClick={() => capture("share_clicked", { slug })}>Share</button>

Before finishing

After writing or editing any component, verify each item before reporting the task as done:

  • Regions used if file has more than one logical part (Types → Helpers → Main export → Sub-components)
  • Default exported component has a TSDoc comment
  • Every prop on the interface has an inline comment
  • cn() used for all class composition (no string interpolation or manual ternaries)
  • type keyword on all type-only imports
  • Presentational components accept and forward a className prop

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.