Claude-skill-registry component-layer
This skill should be used when the user asks to 'create a component', 'add a button', 'build a card', 'add UI element', or 'create a feature component'. Provides guidance for React components using shadcn/ui, Radix primitives, and CVA patterns in components/**/*.tsx.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/component-layer" ~/.claude/skills/majiayu000-claude-skill-registry-component-layer && rm -rf "$T"
manifest:
skills/data/component-layer/SKILL.mdsource content
Component Layer Skill
Scope
- shadcn/ui base components (Radix primitives)components/ui/*.tsx
- Feature-specific componentscomponents/features/*.tsx
- Reusable shared componentscomponents/shared/*.tsx
- Layout componentscomponents/layout/*.tsx
- MDX-specific componentscomponents/mdx/*.tsx
- Context providerscomponents/providers/*.tsx
Decision Tree
Creating a new UI primitive?
- Check if shadcn/ui has it: Visit ui.shadcn.com first
- If available: Use
npx shadcn@latest add <component> - If custom: Create in
following CVA patterncomponents/ui/ - Export from component file (no barrel exports needed)
Creating a feature component?
- Create in
components/features/ - Name descriptively:
,contact-form.tsxarticles-list.tsx - Import UI primitives from
@/components/ui/ - Use server components by default (no "use client" unless needed)
Creating a shared/reusable component?
- Create in
components/shared/ - Keep it generic - no feature-specific logic
- Props interface with clear types
- Consider composition over configuration
Adding client interactivity?
- Add
directive at top of file"use client" - Keep client boundary small - extract client parts
- Prefer server components when possible
Quick Templates
UI Component with CVA (shadcn/ui pattern)
import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; import { cn } from "@/lib/utils"; const componentVariants = cva( "base-classes-here", { variants: { variant: { default: "variant-default-classes", secondary: "variant-secondary-classes", }, size: { default: "size-default-classes", sm: "size-sm-classes", lg: "size-lg-classes", }, }, defaultVariants: { variant: "default", size: "default", }, } ); export interface ComponentProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof componentVariants> {} const Component = React.forwardRef<HTMLDivElement, ComponentProps>( ({ className, variant, size, ...props }, ref) => { return ( <div ref={ref} className={cn(componentVariants({ variant, size, className }))} {...props} /> ); } ); Component.displayName = "Component"; export { Component, componentVariants };
Feature Component (Server)
import { ComponentName } from "@/components/ui/component-name"; interface FeatureProps { title: string; items: Array<{ id: string; name: string }>; } export function FeatureName({ title, items }: FeatureProps) { return ( <section> <h2>{title}</h2> <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> </section> ); }
Client Component
"use client"; import { useState } from "react"; import { Button } from "@/components/ui/button"; interface InteractiveProps { initialValue: string; } export function InteractiveComponent({ initialValue }: InteractiveProps) { const [value, setValue] = useState(initialValue); return ( <div> <span>{value}</span> <Button onClick={() => setValue("clicked")}>Click me</Button> </div> ); }
Layout Component
import { cn } from "@/lib/utils"; interface ContainerProps extends React.HTMLAttributes<HTMLDivElement> { children: React.ReactNode; } export function Container({ className, children, ...props }: ContainerProps) { return ( <div className={cn("mx-auto max-w-7xl px-4", className)} {...props}> {children} </div> ); }
Mistakes
- ❌
when not needed (adds to bundle)"use client" - ❌ Missing
utility for className mergingcn() - ❌ Missing
on forwardRef componentsdisplayName - ❌ Not extending HTML element attributes for proper typing
- ❌ Wrong directory (ui vs features vs shared)
- ❌ Inline styles instead of Tailwind classes
Validation
After changes, run:
.claude/skills/component-layer/scripts/validate-component-patterns.sh <file> pnpm typecheck # Verify TypeScript pnpm check # Biome lint/format
Directory Structure
components/ ├── ui/ # shadcn/ui primitives (button, card, etc.) ├── features/ # Feature-specific (contact-form, articles-list) ├── shared/ # Reusable across features (avatar, social-icons) ├── layout/ # Layout components (container, header, footer) ├── mdx/ # MDX rendering components (code, code-tabs) └── providers/ # Context providers (theme, posthog)