/shep-ui-component
Use when creating, modifying, or reviewing web UI components. Triggers include "new component", "add component", "create UI", "build a widget", "update component", working with files in src/presentation/web/components/, or when the user asks to build any React component for the
Claude Code
$ npx -y skills add shep-ai/shep --skill shep-ui-component --agent claude-code
Codex
$ npx skills add shep-ai/shep --skill shep-ui-component -a codex -y
Cursor
$ npx skills add shep-ai/shep --skill shep-ui-component -a cursor -y
Gemini CLI
$ npx skills add shep-ai/shep --skill shep-ui-component -a gemini-cli -y
GitHub Copilot
$ npx skills add shep-ai/shep --skill shep-ui-component -a github-copilot -y
OpenCode
$ npx skills add shep-ai/shep --skill shep-ui-component -a opencode -y
Windsurf
$ npx skills add shep-ai/shep --skill shep-ui-component -a windsurf -y
SKILL.md
shep-ui-component.SKILL.mdname: shep:ui-component
description: Use when creating, modifying, or reviewing web UI components. Triggers include "new component", "add component", "create UI", "build a widget", "update component", working with files in src/presentation/web/components/, or when the user asks to build any React component for the web UI. Part of the Shep autonomous SDLC platform — https://shep.bot
metadata:
version: '1.0.0'
author: Shep AI (https://shep.bot)
homepage: https://shep.bot
repository: https://github.com/shep-ai/shep
Web UI Component Development
Build React components following the four-tier architecture, with mandatory Storybook stories, `data-testid` attributes, and unit tests.
Four-Tier Hierarchy
Tier 0: ui/ -> shadcn/ui primitives (managed by CLI, rarely hand-edited)
Tier 1: common/ -> Reusable composed components (combine ui/ primitives)
Tier 2: layouts/ -> Page shells, structural wrappers (use ui/ + common/)
Tier 3: features/ -> Domain-specific views bound to routes (use all tiers)
**Import rule:** A tier may only import from lower tiers, never upward.
features/ -> layouts/, common/, ui/
layouts/ -> common/, ui/
common/ -> ui/
ui/ -> external packages only
File Structure
Tier 0 (ui/) — flat files, no subfolder
components/ui/
button.tsx
button.stories.tsx
Tier 1-3 — subfolder per component
components/common/feature-list-item/
feature-list-item.tsx # Implementation
feature-list-item.stories.tsx # Storybook stories (MANDATORY)
index.ts # Barrel export
**Barrel export template:**
export { FeatureListItem } from './feature-list-item';
export type { FeatureListItemProps } from './feature-list-item';After creating any Tier 1-3 component, add it to the tier-level barrel:
- `components/common/index.ts`
- `components/layouts/index.ts`
- `components/features/index.ts`
Component Template
'use client'; // Only if the component uses hooks, event handlers, or browser APIs
import { cn } from '@/lib/utils';
export interface MyComponentProps {
/** Brief prop description. */
label: string;
className?: string;
}
export function MyComponent({ label, className }: MyComponentProps) {
return (
<div
data-testid="my-component"
className={cn('base-classes', className)}
>
{label}
</div>
);
}Rules
1. **Named exports only** — no default exports for components. 2. **`'use client'`** — add only when the component uses hooks, event handlers, or browser APIs. Omit for pure render components. 3. **`className` prop** — accept and merge via `cn()` for composability. 4. **Props interface** — always export the interface alongside the component.
data-testid Convention
Every component MUST include `data-testid` on its root element for test targeting.
Naming scheme: `kebab-case`, scoped to the component
| Component | data-testid | | ----------------------- | ------------------------- | | `FeatureListItem` | `feature-list-item` | | `FeatureStatusGroup` | `feature-status-group` | | `SidebarCollapseToggle` | `sidebar-collapse-toggle` | | `PageHeader` | `page-header` |
Sub-elements: append a suffix
<div data-testid="feature-list-item">
<span data-testid="feature-list-item-label">{name}</span>
<span data-testid="feature-list-item-meta">{duration}</span>
</div>When to add data-testid
- Root element of every component: **always**
- Sub-elements: only when tests need to target them specifically (labels, meta, actions)
- Primitives in `ui/`: use `data-slot` instead (shadcn convention)
In tests, prefer data-testid queries
screen.getByTestId('feature-list-item');
screen.getByTestId('feature-list-item-meta');Fall back to role/text queries when `data-testid` is not set:
screen.getByRole('button', { name: /submit/i });
screen.getByText('Auth Module');Storybook Stories (MANDATORY)
Every component MUST have a colocated `.stories.tsx` file. This is non-negotiable.
Story template
import type { Meta, StoryObj } from '@storybook/react';
import { MyComponent } from './my-component';
// IMPORTANT: Use explicit type annotation, NOT `satisfies Meta<>`
const meta: Meta<typeof MyComponent> = {
title: 'Composed/MyComponent', // See title prefixes below
component: MyComponent,
parameters: {
layout: 'padded', // 'centered' | 'padded' | 'fullscreen'
},
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
label: 'Example',
},
};Title prefixes by tier
| Tier | Prefix | Example | | ----------- | ------------- | -------------------------- | | `ui/` | `Primitives/` | `Primitives/Button` | | `common/` | `Composed/` | `Composed/FeatureListItem` | | `layouts/` | `Layout/` | `Layout/AppSidebar` | | `features/` | `Features/` | `Features/VersionPage` |
Decorators for context-dependent components
If the component requires a React context (e.g. `SidebarProvider`), wrap it:
const meta: Meta<typeof SidebarNavItem> = {
// ...
decorators: [
(Story) => (
<SidebarProvider>
<SidebarMenu>
<Story />
</SidebarMenu>
</SidebarProvider>
),
],
};Story-level decorator overrides (e.g. for alternate states):
export const Collapsed: Story = {
args: { /* ... */ },
decorators: [
(Story) => (
<SidebarProvider defaultOpen={false}>
<Story />
</SidebarProvider>
),
],
};Args and Controls (CRITICAL)
Storybook controls only appear when stories define `args`. **Never use hardcoded render-only stories** — always define `args` so the Controls panel works.
**Standard components (fl
Read more
name: shep:ui-component description: Use when creating, modifying, or reviewing web UI components. Triggers include "new component", "add component", "create UI", "build a widget", "update component", working with files in src/presentation/web/components/, or when the user asks to build any React component for the web UI. Part of the Shep autonomous SDLC platform — https://shep.bot metadata: version: '1.0.0' author: Shep AI (https://shep.bot) homepage: https://shep.bot repository: https://github.com/shep-ai/shep
Web UI Component Development
Build React components following the four-tier architecture, with mandatory Storybook stories, `data-testid` attributes, and unit tests.
Four-Tier Hierarchy
Tier 0: ui/ -> shadcn/ui primitives (managed by CLI, rarely hand-edited) Tier 1: common/ -> Reusable composed components (combine ui/ primitives) Tier 2: layouts/ -> Page shells, structural wrappers (use ui/ + common/) Tier 3: features/ -> Domain-specific views bound to routes (use all tiers)
**Import rule:** A tier may only import from lower tiers, never upward.
features/ -> layouts/, common/, ui/ layouts/ -> common/, ui/ common/ -> ui/ ui/ -> external packages only
File Structure
Tier 0 (ui/) — flat files, no subfolder
components/ui/ button.tsx button.stories.tsx
Tier 1-3 — subfolder per component
components/common/feature-list-item/ feature-list-item.tsx # Implementation feature-list-item.stories.tsx # Storybook stories (MANDATORY) index.ts # Barrel export
**Barrel export template:**
export { FeatureListItem } from './feature-list-item';
export type { FeatureListItemProps } from './feature-list-item';After creating any Tier 1-3 component, add it to the tier-level barrel:
- `components/common/index.ts`
- `components/layouts/index.ts`
- `components/features/index.ts`
Component Template
'use client'; // Only if the component uses hooks, event handlers, or browser APIs
import { cn } from '@/lib/utils';
export interface MyComponentProps {
/** Brief prop description. */
label: string;
className?: string;
}
export function MyComponent({ label, className }: MyComponentProps) {
return (
<div
data-testid="my-component"
className={cn('base-classes', className)}
>
{label}
</div>
);
}Rules
1. **Named exports only** — no default exports for components. 2. **`'use client'`** — add only when the component uses hooks, event handlers, or browser APIs. Omit for pure render components. 3. **`className` prop** — accept and merge via `cn()` for composability. 4. **Props interface** — always export the interface alongside the component.
data-testid Convention
Every component MUST include `data-testid` on its root element for test targeting.
Naming scheme: `kebab-case`, scoped to the component
| Component | data-testid | | ----------------------- | ------------------------- | | `FeatureListItem` | `feature-list-item` | | `FeatureStatusGroup` | `feature-status-group` | | `SidebarCollapseToggle` | `sidebar-collapse-toggle` | | `PageHeader` | `page-header` |
Sub-elements: append a suffix
<div data-testid="feature-list-item">
<span data-testid="feature-list-item-label">{name}</span>
<span data-testid="feature-list-item-meta">{duration}</span>
</div>When to add data-testid
- Root element of every component: **always**
- Sub-elements: only when tests need to target them specifically (labels, meta, actions)
- Primitives in `ui/`: use `data-slot` instead (shadcn convention)
In tests, prefer data-testid queries
screen.getByTestId('feature-list-item');
screen.getByTestId('feature-list-item-meta');Fall back to role/text queries when `data-testid` is not set:
screen.getByRole('button', { name: /submit/i });
screen.getByText('Auth Module');Storybook Stories (MANDATORY)
Every component MUST have a colocated `.stories.tsx` file. This is non-negotiable.
Story template
import type { Meta, StoryObj } from '@storybook/react';
import { MyComponent } from './my-component';
// IMPORTANT: Use explicit type annotation, NOT `satisfies Meta<>`
const meta: Meta<typeof MyComponent> = {
title: 'Composed/MyComponent', // See title prefixes below
component: MyComponent,
parameters: {
layout: 'padded', // 'centered' | 'padded' | 'fullscreen'
},
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
label: 'Example',
},
};Title prefixes by tier
| Tier | Prefix | Example | | ----------- | ------------- | -------------------------- | | `ui/` | `Primitives/` | `Primitives/Button` | | `common/` | `Composed/` | `Composed/FeatureListItem` | | `layouts/` | `Layout/` | `Layout/AppSidebar` | | `features/` | `Features/` | `Features/VersionPage` |
Decorators for context-dependent components
If the component requires a React context (e.g. `SidebarProvider`), wrap it:
const meta: Meta<typeof SidebarNavItem> = {
// ...
decorators: [
(Story) => (
<SidebarProvider>
<SidebarMenu>
<Story />
</SidebarMenu>
</SidebarProvider>
),
],
};Story-level decorator overrides (e.g. for alternate states):
export const Collapsed: Story = {
args: { /* ... */ },
decorators: [
(Story) => (
<SidebarProvider defaultOpen={false}>
<Story />
</SidebarProvider>
),
],
};Args and Controls (CRITICAL)
Storybook controls only appear when stories define `args`. **Never use hardcoded render-only stories** — always define `args` so the Controls panel works.
**Standard components (fl
Other skills on shep.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about shep-ui-component.
- Which coding agents can use shep-ui-component?
- shep-ui-component installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

