From wix-cli
Use when building React site components with editor manifests for Wix CLI applications. Triggers include site component, editor manifest, custom component, visual customization, editor element, CSS properties, data API, site builder component, Wix Editor component. Use this skill whenever the user wants to create a component that site owners can customize through the Wix Editor's visual interface.
npx claudepluginhub wix-playground/skills-architecture-test --plugin wix-cliThis skill uses the workspace's default tool permissions.
Creates production-quality React site components with editor manifests for Wix CLI applications. Site components are React components that integrate with the Wix Editor, allowing site owners to customize content, styling, and behavior through a visual interface.
Builds and reviews Wix CLI app extensions: dashboard pages, modals, plugins, Editor React components, backend APIs, events, service plugins, data collections. Prepares apps for App Market review.
Guides creation of production-ready Power Pages code sites as SPAs using React, Angular, Vue, or Astro, from requirements discovery to deployment with live dev server previews and git commits.
Builds accessible, responsive, performant frontend components using design systems, modern CSS, WCAG patterns, and React/Vue/Svelte examples.
Share bugs, ideas, or general feedback.
Creates production-quality React site components with editor manifests for Wix CLI applications. Site components are React components that integrate with the Wix Editor, allowing site owners to customize content, styling, and behavior through a visual interface.
Site components consist of four required files:
manifest.json)Defines the contract between the React component and Wix ecosystem:
component.tsx)Production-ready React functional component:
wix.elementsRemovalStatestyle.css)Modern CSS with responsive design:
box-sizing: border-box all elementstransition: all, NO media queries (except prefers-reduced-motion)--display: [value] CSS variable, then use display: var(--display) on roottypes.ts)Strict type definitions:
You MUST read MANIFEST_GUIDELINES.md before implementing a site component. It contains the complete manifest structure, all data types, element configurations, and required patterns.
The manifest defines the editor contract using these key sections:
{
"installation": {
"staticContainer": "HOMEPAGE",
"initialSize": {
"width": { "sizingType": "pixels", "pixels": 400 },
"height": { "sizingType": "pixels", "pixels": 300 }
}
}
}
"HOMEPAGE" for automatic installation on Harmony editorsizingType options:
"content" - Auto-size based on content"stretched" - Fill available space"pixels" - Fixed pixel dimension (requires pixels property){
"selector": ".component-name",
"displayName": "Component Name",
"archetype": "Container",
"layout": {
"resizeDirection": "horizontalAndVertical",
"contentResizeDirection": "horizontal"
},
"cssProperties": {
"backgroundColor": {
"displayName": "Background Color",
"defaultValue": "#ffffff"
}
},
"data": {
"columns": {
"dataType": "number",
"displayName": "Number of Columns",
"number": { "minimum": 1, "maximum": 4 }
}
},
"elements": {
"title": {
"elementType": "inlineElement",
"inlineElement": {
"selector": ".component-name__title",
"displayName": "Title",
"data": {
"titleText": {
"dataType": "text",
"displayName": "Title Text"
}
},
"behaviors": {
"selectable": true,
"removable": true
}
}
}
}
}
| Type | Runtime Value | Use Case |
|---|---|---|
text | string | Names, titles, descriptions |
textEnum | string | Predefined options |
number | number | Quantities, dimensions |
booleanValue | boolean | Toggles, flags |
a11y | Object | Accessibility attributes |
link | { href, target, rel } | Navigation links |
image | { uri, url, alt, width, height } | Images |
video | Video object | Media content |
vectorArt | Sanitized SVG object | Icons, graphics |
localDate | string (YYYY-MM-DD) | Date values |
localTime | string (hh:mm) | Time values |
webUrl | string | External URLs |
richText | string (HTML) | Formatted content |
arrayItems | Array | Collections, lists |
direction | string | HTML dir attribute |
menuItems | Array of menu items | Navigation menus |
Common CSS properties for styling customization:
display, gap, padding, margin, width, heightfont, fontSize, fontWeight, textAlign, colorbackgroundColor, backgroundImageborder, borderRadius, boxShadowalignItems, justifyContent, flexDirectionComplete CSS properties reference: See CSS_GUIDELINES.md for all CSS properties, variable patterns, and styling best practices.
Complete reference: See REACT_PATTERNS.md for detailed component architecture, all coding patterns, and implementation examples.
interface ComponentProps {
// Standard props (always present)
className: string;
id: string;
wix?: Wix;
// Component-level data (from editorElement.data)
columns?: number;
layout?: string;
// Element props (from elements definitions)
elementProps?: {
title?: {
titleText?: string;
wix?: Wix;
};
button?: {
buttonText?: string;
buttonLink?: Link;
wix?: Wix;
};
};
}
Extract every distinct UI element into named sub-components:
// Title sub-component
interface TitleProps {
titleText?: string;
className: string;
}
const Title: FC<TitleProps> = ({ titleText = "Default Title", className }) => (
<h2 className={className}>{titleText}</h2>
);
// Main component
const ProductCard: FC<ProductCardProps> = ({
className,
id,
elementProps,
wix
}) => {
const removalState = wix?.elementsRemovalState || {};
return (
<div className={`product-card ${className}`} id={id}>
{!removalState['title'] && (
<Title
className="product-card__title"
{...elementProps?.title}
/>
)}
{!removalState['button'] && (
<Button
className="product-card__button"
{...elementProps?.button}
/>
)}
</div>
);
};
All elements must be conditionally rendered based on removal state:
const removalState = wix?.elementsRemovalState || {};
return (
<div className={`component ${className}`} id={id}>
{!removalState['elementKey'] && <Element />}
</div>
);
Components live in user-resizable containers (300-1200px) within varying viewports:
width: 100%; height: 100%clamp() for fluid scaling.component {
--display: block;
--background-color: #ffffff;
--text-color: #333333;
display: var(--display);
background-color: var(--background-color);
color: var(--text-color);
pointer-events: auto;
}
CRITICAL: CSS selectors must match manifest selectors and React classNames exactly:
className="product-card__title".product-card__title { ... }"selector": ".product-card__title"Complete reference: See DESIGN_SYSTEM.md for visual design principles, creative guidelines, and aesthetic best practices.
| Relationship | Value | Use Case |
|---|---|---|
| Tight (icon + label) | 0.25-0.5rem (4-8px) | Clustering related items |
| Same category | 1-1.5rem (16-24px) | Card sections, form fields |
| Different sections | 2-3rem (32-48px) | Major content blocks |
| Emphasis/Drama | 4rem+ (64px+) | Hero content, luxury feel |
Push beyond obvious solutions:
Each distinct visual part requires a separate manifest element:
editorElement.data - Component-wide configuration only:
elements[key].data - Content for that specific element:
When components need default images, use this format:
// Import in component
import { heroImage } from './assets/defaultImages';
// Usage
<img src={heroImage} alt="Hero" />
Asset specification format:
<imageUrlName>
{ "description": "Modern cityscape at sunset", "width": 1920, "height": 1088 }
</imageUrlName>
Rules:
'./assets/defaultImages'src/extensions/site/components/
└── {component-name}/
├── manifest.json # Component manifest
├── component.tsx # React component
├── style.css # CSS styles
├── types.ts # TypeScript types
└── assets/ # Optional assets
└── defaultImages.ts
Complete working example: See EXAMPLE.md for a full production-ready site component with all patterns, including manifest, React component, CSS, and types.
Request: "Create a product card component with image, title, price, and buy button"
Output:
Request: "Build a hero section with background image, headline, subtitle, and CTA button"
Output:
Request: "Create a features component with configurable number of items"
Output:
Extension registration is MANDATORY and has TWO required steps.
Each site component requires an extensions.ts file in its folder:
import { extensions } from "@wix/astro/builders";
import manifest from "./manifest.json";
export const sitecomponentMyComponent = extensions.siteComponent({
...manifest,
id: "{{GENERATE_UUID}}",
description: "My Component",
type: "platform.MyComponent",
resources: {
client: {
component: "./extensions/site/components/my-component/component.tsx",
componentUrl: "./extensions/site/components/my-component/component.tsx",
},
},
});
CRITICAL: Type Naming Convention
The type field uses the format platform.{PascalCaseFolderName}:
my-component → type: "platform.MyComponent"product-card → type: "platform.ProductCard"hero-section → type: "platform.HeroSection"The folder name is converted to PascalCase (hyphens removed, each word capitalized).
CRITICAL: UUID Generation
The id must be a unique, static UUID v4 string. Generate a fresh UUID for each extension - do NOT use randomUUID() or copy UUIDs from examples.
CRITICAL: After creating the component-specific extension file, you MUST read wix-cli-extension-registration and follow the "App Registration" section to update src/extensions.ts.
Without completing Step 2, the site component will not be available in the Wix Editor.
Complete reference: See TYPESCRIPT_QUALITY.md for comprehensive type safety guidelines and code quality standards.
any types@ts-ignore or @ts-expect-error comments@typescript-eslint/no-unused-vars)img src not https://... (allowed: local imports, wixstatic.com, variables)window/document at module scope/constructor, guard browser APIs in useEffect/handlersdangerouslySetInnerHTML or inline <style> tags - use CSS variables or inline style prop for dynamic valueswindow.fetch (no-restricted-properties)exhaustive-deps: ALL values from component scope used inside useEffect/useCallback MUST be in dependency arrayconst/let (no var), no unknown JSX properties| Mistake | Why It Fails | Fix |
|---|---|---|
| CSS selector doesn't match manifest | Editor can't apply styles to the element | Ensure manifest selector, React className, and CSS selector are identical |
Putting content text in editorElement.data | Content belongs to specific elements, not root | Move text/image/link data into elements[key].data |
Using display: flex directly on root | Breaks editor override mechanism | Use --display: flex CSS variable, then display: var(--display) |
Missing removable: true on optional elements | Site owner can't hide the element | Add behaviors: { removable: true } to optional elements |
Using window/document at module scope | SSR fails during build | Guard browser APIs inside useEffect or event handlers |
Importing from @wix/design-system | Not available in site components | Use plain HTML/CSS or custom components only |
@wix/design-system or @wix/wix-ui-icons-common