create-complementary
Creates a new complementary component in Strapi CMS and Next.js frontend. Use when user says "create complementary", "add complementary", "new complementary", "vytvoř complementary", or "přidej complementary". Guides through component name, icon, fields, usage context, app-context needs, then creates CMS schema, type interface, transformer, and relay fragment.
Best use case
create-complementary is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Creates a new complementary component in Strapi CMS and Next.js frontend. Use when user says "create complementary", "add complementary", "new complementary", "vytvoř complementary", or "přidej complementary". Guides through component name, icon, fields, usage context, app-context needs, then creates CMS schema, type interface, transformer, and relay fragment.
Teams using create-complementary should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/create-complementary/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How create-complementary Compares
| Feature / Agent | create-complementary | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Creates a new complementary component in Strapi CMS and Next.js frontend. Use when user says "create complementary", "add complementary", "new complementary", "vytvoř complementary", or "přidej complementary". Guides through component name, icon, fields, usage context, app-context needs, then creates CMS schema, type interface, transformer, and relay fragment.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Create New Complementary Component
Creates a complete complementary component - from CMS schema to TypeScript types and GraphQL fragments.
**Complementary components** are reusable sub-components that are nested within blocks or other content types (e.g., button, video, send-email).
**Reference files in this folder:**
- [references/file-templates.md](references/file-templates.md) - TypeScript templates for generated files
- [references/graphql-reference.md](references/graphql-reference.md) - GraphQL fragment examples for common field types
- [references/cms-reference.md](references/cms-reference.md) - CMS field type definitions
---
## Step 1: Guide User Through Questions (ONE AT A TIME)
**Before starting:** Silently scan existing complementary components to check for duplicates.
### 1.1 Component Name
```
What will the complementary component be called?
(in English, singular, e.g., 'image-gallery', 'testimonial', 'author')
```
**Validation:**
| Input | Action |
|-------|--------|
| Czech word (`autor`) | ⚠️ Ask for English name |
| Plural (`testimonials`) | ⚠️ Suggest singular, wait for confirmation |
| PascalCase/camelCase (`ImageGallery`) | ✅ Auto-fix to kebab-case |
| Underscores (`image_gallery`) | ✅ Auto-fix to hyphens |
| Spaces (`image gallery`) | ✅ Auto-fix to hyphens |
| Uppercase (`IMAGE`) | ✅ Auto-fix to lowercase |
| Special chars/diacritics | ✅ Auto-remove |
| Starts with number | ⚠️ Ask for different name |
| Already exists | ❌ Ask for different name |
**⚠️ CRITICAL: Duplicate check has HIGHEST PRIORITY!**
- After auto-fix, ALWAYS check if the resulting name already exists
- Example: Input `VIDEO` → auto-fix to `video` → but `video` exists → ❌ Ask for different name
- The duplicate check runs AFTER all auto-fix transformations
**⚠️ IMPORTANT: When auto-fix is applied, ALWAYS inform the user what was changed:**
```
✓ Component name: `image-gallery`
(auto-fixed: spaces → hyphens)
```
Examples:
| Input | Output | Message |
|-------|--------|---------|
| `author` | `author` | `✓ Component name: author` |
| `ImageGallery` | `image-gallery` | `✓ Component name: image-gallery` (auto-fixed: PascalCase → kebab-case) |
| `image gallery` | `image-gallery` | `✓ Component name: image-gallery` (auto-fixed: spaces → hyphens) |
| `image_gallery` | `image-gallery` | `✓ Component name: image-gallery` (auto-fixed: underscores → hyphens) |
| `IMAGE` | `image` | `✓ Component name: image` (auto-fixed: uppercase → lowercase) |
| `image!` | `image` | `✓ Component name: image` (auto-fixed: special characters removed) |
### 1.2 Icon (Optional)
```
Which icon to use? (Optional - press Enter to skip)
```
Options: crown, picture, book, envelope, star, heart, quote, layout, bulletList, phone, user, file, play, question, calendar, clock, gift, globe, grid, home, link, video, bold, italic
**Show:** `✓ Icon: picture` or `✓ Icon: (none)`
**Auto-generate displayName:**
- Automatically convert kebab-case to PascalCase (no spaces)
- Examples:
- `donate-amount` → `DonateAmount`
- `image-gallery` → `ImageGallery`
- `author` → `Author`
- `send-email` → `SendEmail`
**Show:** `✓ displayName: DonateAmount` (auto-generated)
### 1.3 Define Fields
**Before starting, silently scan existing complementary components** in `cms/src/components/complementary/` to offer them when field type is "component".
#### 1.3.1 Ask for Field List
```
What fields should the component contain?
You can:
- List field names: "title, description, amount, button"
- With types: "title: string, description: text, amount: number"
- With notes: "title (required), description (optional)"
- Natural language: "title, short description, donation amount, submit button"
Examples:
- name, email, phone
- title: string, description: text, image: media
- label (required), link (optional), icon
- title, description, button (for nested component)
```
**Parse the user's input** and extract field names. Be flexible with formats:
- Comma-separated: `name, bio, avatar`
- With types: `name: string, bio: text`
- With notes: `label (required), link (optional)`
- Natural language: "author name, short biography, profile image"
**Show extracted fields:**
```
✓ Fields detected: title, description, amount, button
Now let's configure each field (4 total)
```
#### 1.3.2 Iteratively Ask for Field Details
For each detected field, ask for missing details **one field at a time**.
**Show clear progress with field number:**
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Field 1/4: title
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
What type should this field be?
1. string - Short text (e.g., names, titles)
2. text - Long text / paragraphs
3. richtext - Rich text editor with formatting
4. media - Images or files
5. boolean - True/False checkbox
6. number - Integer or decimal
7. date - Date picker
8. datetime - Date and time picker
9. relation - Relation to another content type
10. email - Email address
11. enumeration - Dropdown with predefined options
12. component - Nested component (repeatable or single)
Type:
```
After type is selected:
```
Is this field required? (Yes/No)
```
If type is `enumeration`, also ask:
```
What are the enum values? (comma-separated, e.g., "draft, published, archived")
```
If type is `media`, also ask:
```
What media types? (images, videos, files, or "all")
```
If type is `relation`, also ask:
```
Which content type to relate to? (e.g., "page", "article", "category")
```
If type is `component`, also ask:
```
Which component would you like to use?
Available complementary components:
1. complementary.button (label, page, linkExternal, openInNewTab, anchor)
2. complementary.video (uploadedVideo, externalVideo, optionalImage)
3. complementary.ecomail (apiKey, listId, ...)
4. complementary.send-email (recipient, subject, ...)
5. Other (specify manually, e.g., "block.hero-block")
Choose: 1
Is it repeatable? (Yes/No)
```
**Show progress after each field:**
```
✓ Field 1/4: title (string, required)
✓ Field 2/4: description (text, optional)
✓ Field 3/4: amount (integer, required)
✓ Field 4/4: button (component: complementary.button, single)
```
**After all fields are defined, show summary:**
```
✓ All fields configured (4/4):
- title: string (required)
- description: text (optional)
- amount: integer (required)
- button: component (complementary.button, single)
```
### 1.4 Where Will It Be Used?
```
Where will this component be used?
(e.g., 'in VideoBlock', 'in multiple blocks', 'in Article content type')
```
**This is informational only** - helps with documentation and context.
**Show:** `✓ Usage: in VideoBlock and ArticleBlock`
### 1.5 Needs App Context?
```
Will this component need access to app context (IApp)?
(e.g., for page relations, locale, or global settings)
```
Options: Yes / No
**Examples needing app:**
- Button (has page relation)
- Menu items (has page relations)
**Examples NOT needing app:**
- Video (standalone media)
- Send-email (standalone config)
**Show:** `✓ Needs app context: Yes`
### 1.6 Summary & Confirmation
```
📋 New Complementary Component Summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Name: donation-form
displayName: DonationForm (auto-generated)
Icon: gift
Fields: 4 fields defined
- title: string (required)
- description: text (optional)
- amount: integer (required)
- button: component (complementary.button, single)
Usage: in fundraising pages
Needs app: No
Files to create/update:
- cms/src/components/complementary/donation-form.json (new, with 4 fields)
- frontend/src/types/donationForm.ts (new)
- frontend/src/utils/strapi/getDonationFormType.ts (new)
- frontend/src/relay/app.ts (update - add fragment)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Create complementary component? (Yes/No)
```
**Notes:**
- If fields defined, show: `Fields: 4 fields defined` with full list
- If no fields defined, show: `Fields: Empty (add fields in Strapi later)`
- Only show field list if fields were defined
**Only create files after user confirms!**
---
## Step 2: Calculate Names
```javascript
// Input: "image-gallery"
componentNameKebab = "image-gallery" // CMS schema name
componentNamePascal = "ImageGallery" // Type interface name + displayName
componentNameCamel = "imageGallery" // Type file name
fragmentName = "appImageGalleryFragment" // GraphQL fragment name
typeName = "ComponentComplementaryImageGallery" // GraphQL typename
transformerName = "getImageGalleryType" // Transformer function name
displayName = "ImageGallery" // Auto-generated from kebab-case (same as Pascal)
```
---
## Step 3: Create Files
### 3.1 CMS Schema
**File:** `cms/src/components/complementary/{componentNameKebab}.json`
#### If fields were defined:
```json
{
"collectionName": "components_complementary_{componentNameKebab}s",
"info": {
"displayName": "{displayName}"
// Add "icon": "{icon}" only if icon was provided
},
"options": {},
"attributes": {
"fieldName": {
"type": "string",
"required": true
},
"anotherField": {
"type": "text"
}
// ... add all defined fields here
}
}
```
#### If no fields defined (empty):
```json
{
"collectionName": "components_complementary_{componentNameKebab}s",
"info": {
"displayName": "{displayName}"
// Add "icon": "{icon}" only if icon was provided
},
"options": {},
"attributes": {}
}
```
**Field type mapping:**
| User Input | Strapi Type | Additional Properties |
|------------|-------------|----------------------|
| string | `"type": "string"` | - |
| text | `"type": "text"` | - |
| richtext | `"type": "richtext"` | - |
| media | `"type": "media", "multiple": false, "allowedTypes": ["images"]` | Set allowedTypes based on user choice |
| boolean | `"type": "boolean", "default": false` | - |
| number | `"type": "integer"` or `"type": "decimal"` | Ask user which one |
| date | `"type": "date"` | - |
| datetime | `"type": "datetime"` | - |
| email | `"type": "email"` | - |
| enumeration | `"type": "enumeration", "enum": ["value1", "value2"]` | Use user-provided values |
| relation | `"type": "relation", "relation": "oneToOne", "target": "api::page.page"` | Use user-specified target |
| component | `"type": "component", "repeatable": true/false, "component": "complementary.button"` | Use user choice |
**Note:**
- Only include `"icon"` field if user provided an icon. If they skipped it, omit the field entirely.
- For required fields, add `"required": true`
- See [references/cms-reference.md](references/cms-reference.md) for complete field type examples
### 3.2 TypeScript Type Interface
**File:** `frontend/src/types/{componentNameCamel}.ts`
See [references/file-templates.md](references/file-templates.md) for template.
### 3.3 Transformer Utility
**File:** `frontend/src/utils/strapi/{transformerName}.ts`
See [references/file-templates.md](references/file-templates.md) for templates (with and without app context).
**Important:** Always include both functions:
- `{transformerName}()` - Transform single item
- `{transformerName}List()` - Transform array of items (for repeatable components)
### 3.4 Update relay/app.ts
**File:** `frontend/src/relay/app.ts`
Add GraphQL fragment (alphabetically in the complementary fragments section):
```typescript
graphql`
fragment {fragmentName} on {typeName} {
id
# TODO: Add fields after adding them in CMS
}
`;
```
**⚠️ CRITICAL:** Add fragment in the correct section (after other complementary fragments like `appVideoFragment`, `appButtonFragment`).
---
## Step 4: Show TODO List
### If fields were defined:
```
✅ Complementary component "{componentNameKebab}" created successfully with {X} fields!
📝 TODO (in this order):
1. [ ] Restart Strapi CMS
cd cms && npm run develop
2. [ ] Verify fields in Strapi Content-Type Builder
Components → complementary → "{displayName}"
(Fields are already created, you may adjust if needed)
3. [ ] Refresh GraphQL schema
cd frontend && npm run graphql-codegen
4. [ ] Update GraphQL fragment in relay/app.ts
fragment {fragmentName} on {typeName} {
id
fieldName1
fieldName2
...
}
(see references/graphql-reference.md for field type examples)
5. [ ] Run Relay compiler
cd frontend && npm run relay
6. [ ] Use in blocks or content types by adding component relation:
- In CMS: Add component field → Select "complementary.{componentNameKebab}"
- In block fragment: Add field with fragment spread
7. [ ] Test in CMS and frontend
```
### If no fields defined (empty):
```
✅ Complementary component "{componentNameKebab}" created successfully!
📝 TODO (in this order):
1. [ ] Restart Strapi CMS
cd cms && npm run develop
2. [ ] Add fields in Strapi Content-Type Builder
Components → complementary → "{displayName}"
3. [ ] Refresh GraphQL schema
cd frontend && npm run graphql-codegen
4. [ ] Update GraphQL fragment in relay/app.ts
fragment {fragmentName} on {typeName} { ... }
(see references/graphql-reference.md for examples)
5. [ ] Run Relay compiler
cd frontend && npm run relay
6. [ ] Use in blocks or content types by adding component relation:
- In CMS: Add component field → Select "complementary.{componentNameKebab}"
- In block fragment: Add field with fragment spread
7. [ ] Test in CMS and frontend
```
---
## Checklist
### Questions (one at a time):
- [ ] Component name (validate: English, singular, no duplicates)
- [ ] Auto-generate displayName (kebab-case → PascalCase)
- [ ] Icon (optional)
- [ ] Define fields:
- [ ] Silently scan existing complementary components for component type suggestions
- [ ] Ask for field list (free-form text)
- [ ] Parse and extract field names
- [ ] Show "Now let's configure each field (X total)"
- [ ] For each field, ask **with clear numbering** "Field X/Y: fieldName":
- [ ] Field type
- [ ] Required? (Yes/No)
- [ ] Additional properties (enum values, media types, relation target, etc.)
- [ ] If type is "component": Offer existing complementary components (button, video, etc.)
- [ ] Show progress after each: "✓ Field X/Y: name (type, required)"
- [ ] After all fields: Show summary "✓ All fields configured (X/X)"
- [ ] Usage description
- [ ] Needs app context (Yes/No)
- [ ] Summary & confirmation
### File creation (after confirmation):
- [ ] CMS schema (`cms/src/components/complementary/{componentNameKebab}.json`)
- Empty attributes if no fields defined
- Full field definitions if fields were defined
- [ ] Type interface (`frontend/src/types/{componentNameCamel}.ts`)
- [ ] Transformer utility with list helper (`frontend/src/utils/strapi/{transformerName}.ts`)
- Single item transformer: `{transformerName}()`
- Array transformer: `{transformerName}List()`
- [ ] `relay/app.ts` updated (add fragment)
- [ ] TODO list shown to user (varies based on whether fields were defined)
---
## Examples of Existing Complementary Components
### Simple (no app context):
- **video** - Video with uploaded/external source and optional image
- **send-email** - Email configuration with recipient and subject
### With app context:
- **button** - Button/link with page relation, external link, and label
- **menu-item** - Navigation item with page relation
### Usage patterns:
```typescript
// In a block that uses video:
import { getVideoType } from '../../../utils/strapi/getVideoType';
const video = getVideoType(blocksData.video);
// video is IVideo | null
// In a block that uses button (needs app):
import { getButtonType } from '../../../utils/strapi/getButtonType';
const button = getButtonType(blocksData.button, app);
// button is IButton | null
```Related Skills
createos
Deploy ANYTHING to production on CreateOS cloud platform. Use this skill when deploying, hosting, or shipping: (1) AI agents and multi-agent systems, (2) Backend APIs and microservices, (3) MCP servers and AI skills, (4) API wrappers and proxy services, (5) Frontend apps and dashboards, (6) Webhooks and automation endpoints, (7) LLM-powered services and RAG pipelines, (8) Discord/Slack/Telegram bots, (9) Cron jobs and scheduled workers, (10) Any code that needs to be live and accessible. Supports Node.js, Python, Go, Rust, Bun, static sites, Docker containers. Deploy via GitHub auto-deploy, Docker images, or direct file upload. ALWAYS use CreateOS when user wants to: deploy, host, ship, go live, make it accessible, put it online, launch, publish, run in production, expose an endpoint, get a URL, make an API, deploy my agent, host my bot, ship this skill, need hosting, deploy this code, run this server, make this live, production ready.
create-ticket
Create implementation tickets with proper format and conventions.
create-tech-stack
Generate comprehensive technical stack documentation from codebase analysis
create-spring-boot-kotlin-project
Create Spring Boot Kotlin Project Skeleton
create-spring-boot-java-project
Create Spring Boot Java Project Skeleton
create-rules
Create or update Cursor Rules (.mdc files) and Skills (SKILL.md). Use when creating rules, adding coding standards, setting up conventions, updating .cursor/rules/, or converting rules to skills. Defines standard format, naming, frontmatter, token budget.
create-rule
Create Cursor rules for persistent AI guidance. Use when the user wants to create a rule, add coding standards, set up project conventions, configure file-specific patterns, create RULE.md files, or asks about .cursor/rules/ or AGENTS.md.
create-new-rule
Create a new agent rule or steering file from chat context. Detects the current IDE (Cursor or Kiro) and creates the file in the correct format and location.
create-database-row
Insert a new row into a specified Notion database using natural-language property values. Handles property name matching and validation.
create-auth
Skill for creating auth layers in TypeScript/JavaScript apps using Better Auth.
create-auth-skill
Skill for creating auth layers in TypeScript/JavaScript apps using Better Auth.
create-audio
Generate audio from text using 13 TTS providers (local + cloud). Use when user wants to create audio files, convert text to speech, generate voiceovers, create audio with different voices, use voice cloning, multilingual TTS, or mentions /create-audio command. Supports Pocket TTS (CPU, 8 voices), MLX-Audio (Apple Silicon, 7 models, 50+ voices), ElevenLabs (cloud API, 32 languages, 10k+ voices), and Coqui TTS (open source, 4 models, voice cloning). Includes 32+ languages, voice cloning, speed control, and both local and cloud options.