Create a reusable UI component with factory pattern, theme compatibility, and proper cleanup
Scanned 9/2/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill add-component-ariedam64-gemini --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Add Component Ariedam64 Gemini?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-add-component-ariedam64-gemini-claude-skill-registry)More formats (shields.io, HTML) on the badges page.
---
name: add-component
description: Create a reusable UI component with factory pattern, theme compatibility, and proper cleanup
aliases: [new-component, create-component]
---
# Add Component Skill
## Usage
```
/add-component <ComponentName>
```
## Step 1: Ask Questions
### 1. Check Existing Components First
```
Does an existing component cover ~80% of the need?
→ Check src/ui/components/ before creating new
```
Existing: `ArcadeButton`, `BasePetCard`, `GeminiIconButton`, `Modal`, `ProgressBar`, `SegmentedControl`, `SeeMore`, `SoundPicker`, `Tab`, `TeamListItem`
### 2. Component Purpose
```
Brief description (1 sentence):
```
### 3. Configuration Options
```
What options does it need?
- Required: ___________
- Optional with defaults: ___________
- Event handlers: ___________
```
### 4. Sprites
```
Does it display game sprites? → MGSprite.toCanvas()
```
### 5. Dynamic State
```
Does it need reactive updates?
A) Manual setters only (setLabel, setDisabled, setValue, etc.)
B) Reactive to Globals (subscribe to myInventory, currentTile, weather, etc.)
C) Both
If B/C: Component subscribes to Globals and auto-updates UI
→ Remember to unsubscribe in destroy()!
```
### 6. Child Components (IMPORTANT)
```
Does this component need sub-components?
→ REUSE existing components, never recreate!
Available:
- ArcadeButton, GeminiIconButton → Buttons
- Modal → Dialogs/popups
- ProgressBar → Progress indicators
- SegmentedControl → Tab-like selection
- Tab → Tabs
- SoundPicker → Audio selection
- BasePetCard, TeamListItem → List items
- SeeMore → Expandable content
Example: A "SettingsPanel" component might use:
- SegmentedControl for sections
- Toggle for on/off settings
- ArcadeButton for actions
```
---
## Step 2: Create Structure
```
src/ui/components/<ComponentName>/
├── <ComponentName>.ts # Logic + factory function
├── <componentName>.css.ts # Styles (CSS string)
└── index.ts # Re-exports
```
**Read existing components for templates:** `src/ui/components/*/`
---
## Step 3: Required API
### Options Interface
```typescript
export interface <ComponentName>Options {
// Required (no default)
label: string;
// Optional (have defaults)
variant?: 'primary' | 'secondary';
disabled?: boolean;
// Event handlers
onClick?: () => void;
}
```
### Handle Interface
```typescript
export interface <ComponentName>Handle {
root: HTMLElement; // REQUIRED
set<Property>(value): void; // Public setters (minimal)
destroy(): void; // REQUIRED - cleanup
}
```
### Factory Function
```typescript
export function create<ComponentName>(options: <ComponentName>Options): <ComponentName>Handle
```
---
## Step 4: Style Rules
### Theme Tokens (REQUIRED)
```css
/* NO hardcoded colors */
background: var(--color-bg);
color: var(--color-text);
border: 1px solid var(--color-border);
```
### Responsive (REQUIRED)
```css
min-height: 44px; /* Touch-friendly */
width: 100%; /* Flexible, not fixed */
max-width: 300px; /* Constraint if needed */
```
### Scoped Styles
```css
/* Prefix all classes with component name */
.component-name { }
.component-name__label { }
.component-name--variant { }
```
---
## Step 5: Register
### Export → `src/ui/components/index.ts`
```typescript
export { create<ComponentName> } from './<ComponentName>/<ComponentName>';
export type { <ComponentName>Options, <ComponentName>Handle } from './<ComponentName>/<ComponentName>';
```
---
## Step 6: Validate
### Required
- [ ] `root: HTMLElement` in Handle
- [ ] `destroy()` removes ALL listeners/observers/intervals
- [ ] Factory function returns Handle
### Styling
- [ ] Uses CSS variables (no hardcoded colors)
- [ ] Touch-friendly (min 44px targets)
- [ ] Flexible widths (not fixed px)
- [ ] Focus states visible (`:focus-visible`)
### Composability
- [ ] Safe to nest inside other components
- [ ] No global CSS (scoped classes only)
- [ ] Styles injected into `root`, not `document.head`
- [ ] **Reuses existing components** (never recreate Button, Modal, ProgressBar, etc.)
- [ ] Child components' `destroy()` called in parent's `destroy()`
### If using Sprites
- [ ] Uses `MGSprite.toCanvas()` (never hardcoded paths)
### If using Globals (reactive)
- [ ] Subscribes in factory function
- [ ] **Unsubscribes in `destroy()`** (memory leak otherwise!)
- [ ] Updates UI elements on subscription callback
### If using Child Components
```typescript
import { createProgressBar, createArcadeButton } from '../index';
// In factory:
const progressBar = createProgressBar({ ... });
root.appendChild(progressBar.root);
// In destroy:
destroy() {
progressBar.destroy();
root.remove();
}
```
### If using Globals (reactive UI)
```typescript
import { getMyInventory } from '../../../globals/variables/myInventory';
// In factory:
const unsub = getMyInventory().subscribe((inventory) => {
// Update UI when inventory changes
updateItemCount(inventory.items.length);
});
// In destroy - CRITICAL!
destroy() {
unsub(); // Unsubscribe from Global
root.remove();
}
```
---
## References
- Rules: `.claude/rules/ui/components.md`
- Existing components: `src/ui/components/*/`
- Theme tokens: `src/ui/theme/`
- Reuse workflow: `.claude/workflows/ui/component/reuse-existing-component.md`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!