| name | build-your-own-component |
| description | Generate a complete UI component library with 24 components (Accordion through Tooltip). Supports React or Vanilla JS. Can produce 1-3 design variations for side-by-side comparison. Use when the user wants to create a component library, design system, UI kit, or build reusable UI components. |
Build Your Own Component Library
You are building a complete 24-component UI library. Follow these steps exactly.
Step 1: Gather Requirements
Before writing any code, ask the user these 5 questions. Wait for answers before proceeding.
- Framework: Vanilla JS or React?
- Design sets: How many design variations? (1, 2, or 3) — Note: 3 sets takes significantly longer.
- Style preferences: Any aesthetic direction? (e.g., minimal, playful, corporate, retro, brutalist, glassmorphism). If none provided, invent distinct creative directions for each set.
- Color mode: Dark mode, light mode, or both?
- Icon style: Any icon style preference? (e.g., outlined, filled, rounded, sharp). If none, pick a style that fits each set's aesthetic.
Once you have answers, confirm the plan back to the user before proceeding.
Step 2: Set Up Output Directory
All output goes under /tmp/ComponentLibrary/.
For each set, create a directory named set-{N}-{LibraryName} where {LibraryName} is a creative PascalCase name you invent (e.g., AuroraUI, EmberKit, NovaPrime).
Directory structure per set:
/tmp/ComponentLibrary/
├── comparison.html
├── set-1-AuroraUI/
│ ├── package.json # React only
│ ├── src/
│ │ ├── index.js # Barrel export
│ │ ├── theme.js # Design tokens
│ │ ├── utils.js # Shared utilities
│ │ ├── Accordion/
│ │ │ ├── Accordion.jsx # (.js for Vanilla)
│ │ │ └── Accordion.css
│ │ ├── Alert/
│ │ │ ├── Alert.jsx
│ │ │ └── Alert.css
│ │ └── ... (all 24 components)
├── set-2-EmberKit/ # If 2+ sets
└── set-3-NovaPrime/ # If 3 sets
Step 3: Install Dependencies
- React: Run
npm init -y then npm install react react-dom inside each set directory.
- Vanilla JS: No installation needed. Skip this step.
Step 4: Create Theme (theme.js)
For each set, create src/theme.js defining design tokens as a JavaScript object export.
Required token categories:
export const theme = {
colors: {
primary: { light, main, dark, contrast },
secondary: { light, main, dark, contrast },
success: { light, main, dark, contrast },
warning: { light, main, dark, contrast },
danger: { light, main, dark, contrast },
neutral: { light, main, dark, contrast },
background: { primary, secondary, tertiary },
text: { primary, secondary, disabled },
border: { light, main, dark },
},
spacing: {
xxs: 2, xs: 4, sm: 8, md: 16, lg: 24, xl: 32,
'2xl': 40, '3xl': 48, '4xl': 56, '5xl': 64, '6xl': 72, '7xl': 80,
},
typography: {
fontFamily: '...',
fontSize: { xxs, xs, sm, md, lg, xl, xxl },
lineHeight: { tight, normal, relaxed },
fontWeight: { light, regular, medium, semibold, bold },
},
borders: {
radius: { none, sm, md, lg, xl, full },
width: { thin, medium, thick },
},
shadows: {
sm: '...', md: '...', lg: '...',
},
transitions: {
duration: { fast, normal, slow },
easing: { ease, easeIn, easeOut, easeInOut },
},
};
Multiple sets MUST differ in:
- Color palette (completely different hues/saturation)
- Border radius (e.g., sharp vs. rounded vs. pill)
- Font family (e.g., Inter vs. Space Grotesk vs. Playfair Display)
- Shadow style (e.g., subtle vs. dramatic vs. colored shadows)
- Spacing density (e.g., compact vs. comfortable vs. spacious)
- Animation timing (e.g., snappy vs. smooth vs. bouncy)
Step 5: Create Shared Utilities (utils.js)
Create src/utils.js in each set with these helpers:
Step 6: Build Components in Dependency Order
Read the component specifications from references/component-specs.md for detailed prop tables and behavioral rules.
Read the boilerplate patterns from references/react-templates.md or references/vanilla-templates.md depending on the chosen framework.
Build order (respect dependencies):
Tier 0 — Foundation (no dependencies):
- Spacing — Constants only, no visual component. Exports the spacing scale for use by other components.
- Box — The base container. Replaces
<div> and <span>. Accepts sizing (xxs-xxl), padding/margin props, and an as prop for semantic HTML elements.
- Text — The base text component. Replaces
<p>, <h1>, <span> for text. Accepts size (xxs-xxl), color, bold, italic, strikethrough.
- Icon — Renders SVG icons. Can be pressable (button behavior) or static. Ships with 15 built-in SVG icons:
check, close, chevronDown, chevronUp, chevronLeft, chevronRight, search, plus, minus, info, warning, error, success, star, menu.
Tier 1 — Simple (depend on Tier 0):
5. Badge — Small label. Uses Box + Text internally.
6. Spinner — Loading indicator. CSS animation, multiple sizes.
7. Avatar — User image or initials fallback. Uses Box + Text.
8. Button — 5 color variants (primary/secondary/success/warning/danger), solid/ghost styles, accepts Icon as start/end adornment. Uses Box + Text + Icon.
9. Checkbox — Checkable input with label. Uses Box + Text + Icon.
10. Toggle — Switch toggle. Uses Box.
11. Alert — Status message banner. Uses Box + Text + Icon + Button (for dismiss).
12. EmptyState — Placeholder for empty content areas. Uses Box + Text + Icon.
Tier 2 — Compound (depend on Tier 0-1):
13. ButtonGroup — Groups multiple Buttons together with connected styling.
14. TextInput — Single-line and multi-line text input. Character limit with counter. Uses Box + Text.
15. Card — Content container with optional header/footer. Uses Box + Text.
16. Overlay — Fullscreen semi-transparent mask. Click-to-dismiss. Uses Box.
17. List — Container for ListItems. Uses Box.
18. ListItem — Single row in a List. Uses Box + Text + Icon.
19. Tooltip — Hoverable popup. Positions above/below/left/right. Uses Box + Text.
Tier 3 — Complex (depend on Tier 0-2):
20. Accordion — Expandable/collapsible sections. Uses Box + Text + Icon + Button.
21. Drawer — Slide-in panel from top/bottom/left/right. Uses Overlay + Box.
22. Modal — Centered dialog. Uses Overlay + Box + Text + Button.
23. Toast — Temporary notification. Auto-dismiss with configurable duration. Uses Box + Text + Icon + Button.
24. Select — Dropdown selector. Single and multi-select modes. Renders a SelectMenu (dropdown list) with SelectItem entries. Uses Box + Text + Icon + Overlay.
Build each component by:
- Creating the component directory:
src/{ComponentName}/
- Writing the component file (
.jsx for React, .js for Vanilla)
- Writing the CSS file (
.css)
- Adding the export to
src/index.js
Step 7: Universal Component Rules
These rules apply to EVERY component in EVERY set:
Composition rules:
- Always use
Box instead of raw <div> or <span> elements.
- Always use
Text instead of raw text nodes, <p>, <h1>, etc.
- This ensures theming is consistent and spacing props work everywhere.
Spacing props:
Most components accept these shorthand props that map to CSS padding/margin:
- Padding:
p, pt, pb, pl, pr, px, py
- Margin:
m, mt, mb, ml, mr, mx, my
- Values come from the spacing scale in
theme.js
CSS naming convention:
.cl-ComponentName /* base */
.cl-ComponentName--variant /* modifier */
.cl-ComponentName--size-lg /* size modifier */
.cl-ComponentName__element /* child element */
.cl-ComponentName__element--state /* child state */
The cl- prefix stands for "component library" and prevents class name collisions.
File structure per component:
ComponentName/
├── ComponentName.jsx (.js) # Component logic
└── ComponentName.css # Component styles
API consistency:
All sets share the EXACT same component API (same props, same prop types, same defaults). Only the visual theme differs between sets. A user should be able to swap between sets by changing the import path alone.
Step 8: Build Comparison Page
After all components are built:
- Read the comparison page template from the skill's
assets/comparison-page.html file.
- Set
data-sets="{N}" on the <html> tag to match the number of sets.
- Generate a
:root { ... } block and (if dark mode enabled) a [data-theme="dark"] { ... } block from each set's theme.js.
- Inject the generated CSS between the markers
/* === THEME CONFIG — GENERATED BY SKILL === */ and /* === END THEME CONFIG === */. The template has NO placeholder values — only the two marker comments. Insert the generated CSS between them.
- Write the completed page to
/tmp/ComponentLibrary/comparison.html.
Generating the :root block
For each set N (1-based), read set-{N}-{Name}/src/theme.js and emit these CSS custom properties inside a single :root { } rule:
| CSS Custom Property | Source in theme.js |
|---|
--sets | Total number of sets (integer) |
--s{N}-name | theme.name (wrap in quotes) |
--s{N}-font | theme.typography.fontFamily |
--s{N}-primary | theme.colors.primary.main |
--s{N}-primary-light | theme.colors.primary.light |
--s{N}-primary-dark | theme.colors.primary.dark |
--s{N}-primary-contrast | theme.colors.primary.contrast |
--s{N}-secondary | theme.colors.secondary.main |
--s{N}-secondary-light | theme.colors.secondary.light |
--s{N}-success | theme.colors.success.main |
--s{N}-success-light | theme.colors.success.light |
--s{N}-warning | theme.colors.warning.main |
--s{N}-warning-light | theme.colors.warning.light |
--s{N}-danger | theme.colors.danger.main |
--s{N}-danger-light | theme.colors.danger.light |
--s{N}-neutral | theme.colors.neutral.main |
--s{N}-neutral-light | theme.colors.neutral.light |
--s{N}-bg | theme.colors.background.primary |
--s{N}-bg2 | theme.colors.background.secondary |
--s{N}-text | theme.colors.text.primary |
--s{N}-text2 | theme.colors.text.secondary |
--s{N}-border | theme.colors.border.light |
--s{N}-radius-sm | theme.borders.radius.sm |
--s{N}-radius-md | theme.borders.radius.md |
--s{N}-radius-lg | theme.borders.radius.lg |
--s{N}-radius-xl | theme.borders.radius.xl |
--s{N}-shadow | theme.shadows.md |
--s{N}-shadow-lg | theme.shadows.lg |
--s{N}-transition | {theme.transitions.duration.normal} {theme.transitions.easing.ease} |
--s{N}-glass-bg | none (or custom value if glassmorphism set) |
--s{N}-glass-border | transparent (or custom value if glassmorphism set) |
--s{N}-glass-blur | 0 (or custom value if glassmorphism set) |
For any unused set slots (e.g., only 2 sets but template renders up to 3), set all --s{N}-* values to transparent/none/0 so the hidden columns don't break.
Generating the [data-theme="dark"] block
For each set N, read theme.darkColors and emit overrides inside a single [data-theme="dark"] { } rule:
| CSS Custom Property | Source in theme.js |
|---|
--s{N}-bg | theme.darkColors.background.primary |
--s{N}-bg2 | theme.darkColors.background.secondary |
--s{N}-text | theme.darkColors.text.primary |
--s{N}-text2 | theme.darkColors.text.secondary |
--s{N}-border | theme.darkColors.border.light |
--s{N}-primary-light | theme.darkColors.primary.light |
--s{N}-secondary-light | theme.darkColors.secondary.light |
--s{N}-success-light | theme.darkColors.success.light |
--s{N}-warning-light | theme.darkColors.warning.light |
--s{N}-danger-light | theme.darkColors.danger.light |
--s{N}-neutral-light | theme.darkColors.neutral.light |
--s{N}-shadow | Same shadow dimensions, but use rgba(0,0,0,0.4) |
--s{N}-shadow-lg | Same shadow dimensions, but use rgba(0,0,0,0.5) |
If the user chose "light mode only", skip the [data-theme="dark"] block entirely. For unused set slots, set all dark values to transparent/none.
Generating component demo sections
The template contains NO hardcoded component demos — only marker comments telling you where to generate them. You must generate:
-
Sidebar links: Inside the <nav class="sidebar">, add one <a href="#component-id" class="sidebar__link">ComponentName</a> per component (alphabetical).
-
Component sections: Replace the <!-- GENERATED BY SKILL: Component demo sections go here. ... --> comment with 24 <section> blocks. Each section needs:
id matching the component name in lowercase
<h2 class="component-section__heading"> with component name
- Props table:
<table class="props-table"> with key props (Prop, Type, Default, Description)
- Comparison grid with one
comparison-cell per set, each containing an interactive HTML demo styled with var(--s{N}-*) CSS variables
-
JS handlers: Replace the // GENERATED BY SKILL: Add JS handlers here... comment in the <script> block with event listeners for interactive components.
Interactive component patterns
Use these CSS classes/conventions in your generated HTML — the template's CSS already styles them:
| Component | HTML pattern |
|---|
| Button | Plain <button> elements — CSS handles :hover and :active automatically |
| Accordion | .demo-accordion > .demo-accordion__header + .demo-accordion__panel |
| Modal | .demo-modal-trigger[data-modal="{N}"] button + .demo-modal-overlay#demo-modal-{N} > .demo-modal-panel |
| Drawer | .demo-drawer-trigger[data-drawer="{N}"] button + .demo-drawer-overlay#demo-drawer-{N} > .demo-drawer-panel |
| Select | .demo-select > .demo-select__trigger + .demo-select__dropdown > .demo-select__option[data-value] |
| Checkbox | .demo-checkbox label > .demo-checkbox__box[data-primary][data-contrast] span |
| TextInput | Real <input type="text"> elements (never use readonly) |
| Toggle | Clickable with CSS transition on the thumb |
Notes:
- The template has NO placeholder theme values or component demos — you generate everything from
theme.js and component-specs.md.
- The page must work by simply opening the HTML file in a browser with no build step.
- All HTML must be self-contained — no external JS/CSS dependencies beyond the Google Fonts link in the template.
Step 9: Create Barrel Export (index.js)
Create src/index.js in each set that re-exports all 24 components:
export { Accordion } from './Accordion/Accordion';
export { Alert } from './Alert/Alert';
export { Avatar } from './Avatar/Avatar';
export { Tooltip } from './Tooltip/Tooltip';
Also export the theme and utilities:
export { theme } from './theme';
export { spacingToStyle, cn, generateId } from './utils';
Step 10: Final Verification
After building everything, verify:
- All 24 component directories exist in each set
- Each component has both a
.jsx/.js and .css file
index.js exports all components
theme.js has all required token categories
comparison.html exists and has all placeholders replaced
- Component reuse is correct: Box wraps containers, Text renders text, Overlay is shared by Modal and Drawer
Report the final structure to the user and suggest they open /tmp/ComponentLibrary/comparison.html in a browser.
Important Notes
- Do NOT skip components. All 24 must be built for each set.
- Do NOT use external component libraries. Everything is built from scratch.
- Do NOT use Tailwind, styled-components, or CSS-in-JS libraries. Use plain CSS files.
- Do NOT add extra components beyond the 24 specified.
- Each component MUST import and use Box and Text for internal structure (except Box and Text themselves, and Spacing which is constants-only).
- Icon component ships 15 SVG icons inline — no icon library dependencies.
- When generating creative library names and style directions, be inventive and distinct. Avoid generic names like "StyleKit" or "UILib".
- For the comparison page, ensure all HTML is valid and self-contained. The page must work by simply opening the file in a browser with no build step.