Back to list
sgcarstrends

component-docs

by sgcarstrends

Monorepo for SG Cars Trends backend services

14🍴 1📅 Jan 23, 2026

SKILL.md


name: component-docs description: Generate or update component documentation with usage examples, props tables, and Storybook stories. Use when documenting new components or improving existing component docs. allowed-tools: Read, Edit, Write, Grep, Glob

Component Documentation Skill

This skill helps you create and maintain component documentation in packages/ui/.

When to Use This Skill

  • Writing documentation for new components
  • Creating usage examples and code snippets
  • Documenting component props and variants
  • Setting up Storybook stories
  • Generating API documentation
  • Maintaining component README files

Documentation Structure

packages/ui/
├── src/
│   ├── components/
│   │   ├── button.tsx          # Component implementation
│   │   ├── button.stories.tsx  # Storybook stories (optional)
│   │   └── __tests__/
│   │       └── button.test.tsx # Component tests
├── docs/
│   ├── components/
│   │   ├── button.md           # Component documentation
│   │   └── card.md
│   └── guides/
│       ├── getting-started.md
│       └── customization.md
└── README.md                    # Package overview

Component Documentation Template

Basic Component Documentation

# Button

A customizable button component built with Radix UI primitives.

## Installation

This component is part of the `@sgcarstrends/ui` package.

\`\`\`bash
pnpm add @sgcarstrends/ui
\`\`\`

## Usage

\`\`\`tsx
import { Button } from "@sgcarstrends/ui";

export function Example() {
  return <Button>Click me</Button>;
}
\`\`\`

## Variants

### Default

\`\`\`tsx
<Button variant="default">Default Button</Button>
\`\`\`

### Destructive

\`\`\`tsx
<Button variant="destructive">Delete</Button>
\`\`\`

### Outline

\`\`\`tsx
<Button variant="outline">Outline Button</Button>
\`\`\`

## Sizes

\`\`\`tsx
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">
  <Icon />
</Button>
\`\`\`

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | `"default" \| "destructive" \| "outline" \| "secondary" \| "ghost" \| "link"` | `"default"` | The visual style of the button |
| size | `"default" \| "sm" \| "lg" \| "icon"` | `"default"` | The size of the button |
| asChild | `boolean` | `false` | Render as child element |
| disabled | `boolean` | `false` | Whether button is disabled |

## Examples

### With Icon

\`\`\`tsx
import { Button } from "@sgcarstrends/ui";
import { DownloadIcon } from "lucide-react";

export function DownloadButton() {
  return (
    <Button>
      <DownloadIcon className="mr-2 h-4 w-4" />
      Download
    </Button>
  );
}
\`\`\`

### Loading State

\`\`\`tsx
"use client";

import { useState } from "react";
import { Button } from "@sgcarstrends/ui";

export function LoadingButton() {
  const [isLoading, setIsLoading] = useState(false);

  return (
    <Button disabled={isLoading} onClick={() => setIsLoading(true)}>
      {isLoading ? "Loading..." : "Submit"}
    </Button>
  );
}
\`\`\`

### As Link

\`\`\`tsx
import { Button } from "@sgcarstrends/ui";
import Link from "next/link";

export function LinkButton() {
  return (
    <Button asChild>
      <Link href="/about">Learn More</Link>
    </Button>
  );
}
\`\`\`

## Accessibility

- Uses semantic `<button>` element
- Supports keyboard navigation (Enter, Space)
- Proper focus states
- ARIA attributes supported via props

## Styling

The Button component uses Tailwind CSS and CSS variables for theming. Customize via:

\`\`\`tsx
<Button className="custom-classes">Custom Styled</Button>
\`\`\`

## Related Components

- [Link Button](#)
- [Icon Button](#)
- [Button Group](#)

JSDoc Comments

Add comprehensive JSDoc comments to components:

/**
 * A customizable button component with multiple variants and sizes.
 *
 * @component
 * @example
 * ```tsx
 * <Button variant="default" size="md">
 *   Click me
 * </Button>
 * ```
 */
export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  /**
   * Render the button as a child element (e.g., Link)
   * @default false
   */
  asChild?: boolean;

  /**
   * The visual style variant of the button
   * @default "default"
   */
  variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";

  /**
   * The size of the button
   * @default "default"
   */
  size?: "default" | "sm" | "lg" | "icon";
}

/**
 * Button component
 *
 * @param {ButtonProps} props - Button props
 * @returns {React.ReactElement} Button element
 *
 * @example
 * Basic usage
 * ```tsx
 * <Button>Click me</Button>
 * ```
 *
 * @example
 * With variant
 * ```tsx
 * <Button variant="destructive">Delete</Button>
 * ```
 *
 * @example
 * As a link
 * ```tsx
 * <Button asChild>
 *   <Link href="/about">About</Link>
 * </Button>
 * ```
 */
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button";
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    );
  }
);

Button.displayName = "Button";

Storybook Stories

Installing Storybook (if not present)

cd packages/ui

# Initialize Storybook
npx storybook@latest init

Basic Story

// packages/ui/src/components/button.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./button";

const meta = {
  title: "Components/Button",
  component: Button,
  parameters: {
    layout: "centered",
  },
  tags: ["autodocs"],
  argTypes: {
    variant: {
      control: "select",
      options: ["default", "destructive", "outline", "secondary", "ghost", "link"],
    },
    size: {
      control: "select",
      options: ["default", "sm", "lg", "icon"],
    },
  },
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
  args: {
    children: "Button",
  },
};

export const Destructive: Story = {
  args: {
    variant: "destructive",
    children: "Delete",
  },
};

export const Outline: Story = {
  args: {
    variant: "outline",
    children: "Outline",
  },
};

export const Small: Story = {
  args: {
    size: "sm",
    children: "Small Button",
  },
};

export const Large: Story = {
  args: {
    size: "lg",
    children: "Large Button",
  },
};

export const WithIcon: Story = {
  args: {
    children: (
      <>
        <span className="mr-2">📥</span>
        Download
      </>
    ),
  },
};

export const Disabled: Story = {
  args: {
    children: "Disabled Button",
    disabled: true,
  },
};

Complex Story with Interactions

import type { Meta, StoryObj } from "@storybook/react";
import { within, userEvent, expect } from "@storybook/test";
import { Card, CardHeader, CardTitle, CardContent } from "./card";

const meta = {
  title: "Components/Card",
  component: Card,
  parameters: {
    layout: "centered",
  },
  tags: ["autodocs"],
} satisfies Meta<typeof Card>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
  render: () => (
    <Card className="w-[350px]">
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
      </CardHeader>
      <CardContent>
        <p>Card content goes here.</p>
      </CardContent>
    </Card>
  ),
};

export const WithInteraction: Story = {
  render: () => (
    <Card className="w-[350px]">
      <CardHeader>
        <CardTitle>Interactive Card</CardTitle>
      </CardHeader>
      <CardContent>
        <button data-testid="card-button">Click me</button>
      </CardContent>
    </Card>
  ),
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByTestId("card-button");

    await userEvent.click(button);
    await expect(button).toBeInTheDocument();
  },
};

TypeDoc for API Documentation

Setup TypeDoc

cd packages/ui

pnpm add -D typedoc

Add to package.json:

{
  "scripts": {
    "docs:generate": "typedoc --out docs/api src/index.ts"
  }
}

TypeDoc Configuration

// packages/ui/typedoc.json
{
  "entryPoints": ["src/index.ts"],
  "out": "docs/api",
  "exclude": ["**/*.test.ts", "**/*.stories.tsx"],
  "excludePrivate": true,
  "excludeProtected": true,
  "plugin": ["typedoc-plugin-markdown"],
  "readme": "README.md",
  "theme": "default"
}

Generate documentation:

pnpm docs:generate

README Documentation

Package README Template

# @sgcarstrends/ui

Shared UI component library for SG Cars Trends platform.

## Installation

\`\`\`bash
pnpm add @sgcarstrends/ui
\`\`\`

## Usage

\`\`\`tsx
import { Button, Card, Dialog } from "@sgcarstrends/ui";

export function Example() {
  return (
    <Card>
      <Button>Click me</Button>
    </Card>
  );
}
\`\`\`

## Components

### Core Components
- [Button](docs/components/button.md) - Customizable button with variants
- [Card](docs/components/card.md) - Container for content
- [Dialog](docs/components/dialog.md) - Modal dialog
- [Badge](docs/components/badge.md) - Status badges

### Form Components
- [Input](docs/components/input.md) - Text input
- [Textarea](docs/components/textarea.md) - Multi-line text input
- [Select](docs/components/select.md) - Dropdown select
- [Checkbox](docs/components/checkbox.md) - Checkbox input

### Layout Components
- [Separator](docs/components/separator.md) - Visual divider
- [Tabs](docs/components/tabs.md) - Tabbed interface

## Styling

Components use Tailwind CSS and CSS variables for theming.

### Dark Mode

Dark mode is supported via CSS variables defined in \`globals.css\`.

### Customization

Customize component styles:

\`\`\`tsx
<Button className="custom-classes">Custom Button</Button>
\`\`\`

## Development

\`\`\`bash
# Install dependencies
pnpm install

# Run tests
pnpm test

# Run Storybook
pnpm storybook

# Build package
pnpm build
\`\`\`

## Contributing

See [CONTRIBUTING.md](../../CONTRIBUTING.md)

## License

MIT

Props Table Generator

Create a script to generate props tables from TypeScript:

// scripts/generate-props-table.ts
import * as ts from "typescript";
import * as fs from "fs";

function generatePropsTable(componentPath: string) {
  const program = ts.createProgram([componentPath], {});
  const sourceFile = program.getSourceFile(componentPath);

  if (!sourceFile) return;

  const checker = program.getTypeChecker();

  ts.forEachChild(sourceFile, (node) => {
    if (ts.isInterfaceDeclaration(node) && node.name.text.endsWith("Props")) {
      console.log(`| Prop | Type | Default | Description |`);
      console.log(`|------|------|---------|-------------|`);

      node.members.forEach((member) => {
        if (ts.isPropertySignature(member) && member.name) {
          const name = member.name.getText(sourceFile);
          const type = checker.typeToString(
            checker.getTypeAtLocation(member)
          );
          const docs = ts.displayPartsToString(
            member.symbol?.getDocumentationComment(checker)
          );

          console.log(`| ${name} | \`${type}\` | - | ${docs} |`);
        }
      });
    }
  });
}

// Usage
generatePropsTable("src/components/button.tsx");

Component Checklist

When documenting a component, ensure:

  • Component file has JSDoc comments
  • Props interface is fully documented
  • Markdown documentation file exists
  • Usage examples provided
  • Props table included
  • Variants documented
  • Accessibility notes added
  • Related components linked
  • Storybook stories created (if using Storybook)
  • Exported from package index
  • Added to README component list

Documentation Patterns

Code Examples

Always provide working code examples:

## Example: Search Form

\`\`\`tsx
"use client";

import { useState } from "react";
import { Input, Button } from "@sgcarstrends/ui";

export function SearchForm() {
  const [query, setQuery] = useState("");

  return (
    <form className="flex gap-2">
      <Input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />
      <Button type="submit">Search</Button>
    </form>
  );
}
\`\`\`

Do's and Don'ts

## Best Practices

### ✅ Do

- Use semantic HTML elements
- Provide accessible labels
- Test keyboard navigation
- Support dark mode

### ❌ Don't

- Nest buttons inside buttons
- Forget hover states
- Override core styles directly
- Skip accessibility attributes

Automated Documentation

Using react-docgen

pnpm add -D react-docgen-typescript
// scripts/generate-docs.ts
import { parse } from "react-docgen-typescript";

const options = {
  savePropValueAsString: true,
  shouldExtractLiteralValuesFromEnum: true,
};

const docs = parse("src/components/button.tsx", options);

console.log(JSON.stringify(docs, null, 2));

Testing Documentation

Ensure examples work:

// __tests__/docs/examples.test.tsx
import { render } from "@testing-library/react";

// Test all documented examples
describe("Documentation Examples", () => {
  it("renders basic button example", () => {
    const { container } = render(<Button>Click me</Button>);
    expect(container.querySelector("button")).toBeInTheDocument();
  });

  it("renders button with icon example", () => {
    const { container } = render(
      <Button>
        <span className="mr-2">📥</span>
        Download
      </Button>
    );
    expect(container.textContent).toContain("Download");
  });
});

References

  • Related files:
    • packages/ui/docs/ - Component documentation
    • packages/ui/README.md - Package overview
    • packages/ui/src/components/*.stories.tsx - Storybook stories
    • packages/ui/CLAUDE.md - UI package documentation

Best Practices

  1. Clear Examples: Provide complete, working code examples
  2. Props Documentation: Document every prop with type and description
  3. Accessibility: Include accessibility notes
  4. Visual Examples: Use Storybook for interactive demos
  5. Keep Updated: Update docs when components change
  6. Search Friendly: Use clear headings and keywords
  7. Code Quality: Test documented examples
  8. Version History: Track changes in documentation

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon