All skills
wix avatar

/wix-app

@dc6f1fa official
by Wix.comwix/skills33 stars
33

Build and review Wix CLI app extensions — dashboard pages, modals, plugins, menu plugins, custom element widgets, Editor React components, site plugins, embedded scripts, backend APIs, backend events, service plugins, data collections, and App Market readiness. Use when building ANY feature or extension for a Wix CLI app or preparing a Wix app for App Market review. Triggers on: add, build, create, implement, help me, dashboard, widget, plugin, backend, API, event, collection, embedded script, service plugin, Editor React component, checkout, shipping, tax, discount, SPI, CMS, schema, tracking, popup, admin panel, menu item, modal, validate, test, verify, register extension, App Market, app review, submission readiness.

Use this Skill: https://skilld.dev/gh/wix/skills/wix-app

This session only. Nothing lands on disk.

referenceseditor-react-componentCOMPONENT-CONTRACT.md

≈2.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Component Contract

Use this reference when defining props, defaults, named-part wiring, complex data, or internal file boundaries.

Public Props Contract

Keep identity and platform contracts together with component-specific data and behavior. Do not add children unless the component is explicitly a container.

Use this shape:

import type { A11y, Direction } from '@wix/editor-react-types';

export type PlanCardProps = {
  id: string;
  className?: string;
  direction?: Direction;
  a11y?: A11y;

  heading?: string;
  plans?: Array<Plan>;
  onClick?: (event: React.MouseEvent) => void;
  onMouseIn?: (event: React.MouseEvent) => void;
  onMouseOut?: (event: React.MouseEvent) => void;
  onFocus?: (event: React.FocusEvent) => void;
  onBlur?: (event: React.FocusEvent) => void;

  elementProps?: {
    cta?: { className?: string; href?: string };
  };
};

Rules:

  • Follow ACCESSIBILITY.md. Expose only ariaLabel, for a control without a visible name, through the typed a11y contract. Keep semantics and state in code. Do not add one-off ARIA props or spread the whole object.
  • Expose only content and behavior that the site owner controls. Keep derived values internal.
  • Default to common optional SDK callbacks by capability; add specialized ones when requested. Keep implementation handlers internal.
  • Use Array<T>, not T[], for exported arrays.
  • A CTA with a real destination is a native link with that href. If it only performs an action, use a native button. Never use href="#" as a fallback; it creates a focusable link without a meaningful destination.

Numeric Range Constraints

Use inline @min and @max JSDoc tags for fixed-domain numeric props. Manifest generation reads the tags automatically.

export type RatingProps = {
  /** @min 0 @max 5 */
  rating: number;
};

Use fixed bounds for ratings, percentages, playback speed, columns, etc. Omit for open-ended values or indices tied to a dynamic collection.

Named Parts and elementProps

Treat an independently editable inner element as a named part. Wiring rules:

  • Root receives top-level id, className, direction, a11y — no elementProps entry.
  • Every named inner part has an elementProps entry (even if only className is needed); structural/decorative non-parts use only a CSS Module class.

On a raw HTML element, spread the entry and explicitly merge its injected className. Keep the entry key short while prefixing the global class with the component name.

<a
  {...elementProps?.cta}
  className={classNames(
    'plan-card-cta',
    styles.cta,
    elementProps?.cta?.className,
  )}
>
  {label}
</a>

When a named part renders another component built with this skill, spread the entry and let that component merge its incoming className on its root.

<PlanRow {...elementProps?.planRow} item={plan} />

Do not merge the same class at both the call site and the sub-component root.

Content and Data

Compute derived values internally when a small pure expression can derive them from props or state (e.g. expose price and quantity; compute subtotal; use numeric types when arithmetic is required).

Data-Driven Components

Export named content props rather than children for leaf components — text (label, title, placeholder), media (image, video, icon), links (link, href), collections (items, options, menuItems). Internal sub-components may still use children for composition.

Container Components

Use React.ReactNode only for containers or slots accepting arbitrary nested components. Put dir="ltr" on elements rendering ReactNode so nested content does not inherit the component's direction.

Array Props

Array elements must be objects with named keys for semantics and extensibility.

type GalleryProps = {
  images: Array<{ image: Image; caption?: string }>;
  tags: Array<{ label: string }>;
};

Do not export Array<string>, Array<Image>, Array<Array<T>>, or nested arrays inside items.

The parent owns the array. Item sub-components receive one item, not the collection. Do not add an id field for React keys—use the item's semantic named fields instead. Prefer: (1) a stable unique field (value, uri, label, …), (2) else slug a user-facing string (name, label), (3) else the array index.

Active-Item Components

Apply this contract when an array-driven UI shows one item body at a time (tabs, slides, steps). Skip for always-visible lists, multi-select, or multi-expand.

  • Every item needs name: string (used for hat-selector labels).
  • Import and use ActiveItemIndex<'arrayPropName'> from @wix/react-component-utils. The type argument must match the array prop name exactly, and defaultProps must set the index to 0.
  • Render all bodies with .map(). Active body gets --active; inactive bodies get functional CSS visibility, aria-hidden, and inert.
  • With React 18 types, spread ...(!isActive ? { inert: 'true' } : {}) onto an inactive body; this emits the boolean HTML attribute without a TypeScript prop error. Use the app's typecheck instead of a scratch TypeScript project.
  • Provide keyboard navigation and the matching ARIA pattern.
import type { A11y, Direction } from '@wix/editor-react-types';
import type { ActiveItemIndex } from '@wix/react-component-utils';

export type Step = { name: string; body: string };

export type StepsProps = {
  id: string;
  className?: string;
  direction?: Direction;
  a11y?: A11y;
  steps: Array<Step>;
  activeItem: ActiveItemIndex<'steps'>;
};

export const defaultProps = {
  steps: [{ name: 'Step 1', body: 'First step' }],
  activeItem: 0,
} satisfies Omit<StepsProps, 'id' | 'className'>;

Wix Data Types

Use Image, Link, Video, Audio, VectorArt, RichText from @wix/editor-react-types. Model authored media with the corresponding Wix media type, whether it is a top-level prop or a field in an array item. Name the field for the media itself (image, video, audio, and so on), not for one representation of it.

Common fields in the installed types: Image has required url: string and optional uri, alt, width, height; Link has optional href, target ('_self' | '_blank'), and rel. Use image.url for <img src>, image.alt for its alternative text, and link.href for <a href>.

Do not represent media as a URL/source string or split its metadata across primitive props. Preserve the media object through the public contract so the component can consume all of its supported data. Inspect the installed media type declaration only if a needed field is not covered here or a typecheck reports an error.

Defaults and Resources

Export defaultProps from <component-name>.props.ts. Both component.tsx and the extension consume this object; never duplicate fallbacks in JSX.

All rendered media must come from Wix-hosted services, local assets, or props. No external hosts or third-party runtime dependencies.

For Image defaults, populate only uri, url, and alt; the editor fills dimensions and focal-point metadata.

export const defaultProps = {
  image: {
    url: 'https://static.wixstatic.com/media/11062b_2f97b87dcea2446fa48e9ad9c5457ae1~mv2.jpg',
    uri: '11062b_2f97b87dcea2446fa48e9ad9c5457ae1~mv2.jpg',
    alt: 'Tropical beach viewed from above',
  },
} as const satisfies Omit<ExampleComponentProps, 'id' | 'className'>;

Use distinct Wix-hosted defaults per image slot; keep all fallback data in defaultProps so rendering never hardcodes a second fallback in JSX.

Use this pool in order, cycling only when more than five defaults are needed:

# fileName Description
1 11062b_2f97b87dcea2446fa48e9ad9c5457ae1~mv2.jpg Tropical beach aerial
2 11062b_73f31c7e7d3544c69dc8ecd8d34c5717~mv2.jpg Dead Sea landscape
3 11062b_3682ebfcb08e4da5b3168b62819a1e68~mv2.jpg Palm tree sunset
4 11062b_45e67783d39c4963ab9e4fc418173233~mv2.jpg Abstract pink waves
5 11062b_4c11f014b0d04948b2e6f554076bc40a~mv2.jpg Coastal village aerial

For one image use entry 1; for multiple slots use a different entry each.

Internal File Splitting

Split independently understandable units when it makes the main component easier to read or test. Keep internal files in the component folder using .module.css.

component-name/
├── components/
│   └── plan-row/
│       ├── plan-row.tsx
│       └── plan-row.module.css
├── hooks/
│   └── use-playback.ts
├── component-name.props.ts
├── component-name.tsx
└── component-name.module.css

Do not extract tiny fragments merely to satisfy a line-count threshold.

Checklist

  • Identity, direction, a11y, and SDK callbacks follow the public props shape.
  • Props hold authored data/behavior; derived values stay internal.
  • Fixed-domain numeric props use @min/@max JSDoc tags.
  • Named inner parts have elementProps wiring; leaf components avoid exported children.
  • One-body-visible arrays use the active-item contract and render all bodies.
  • Array elements are objects with semantic named fields. No separate id field added to item types; React keys use item fields (stable unique → slug → index), not a typed id.
  • Authored media uses the corresponding Wix media type, not URL/source strings or flattened metadata.
  • Defaults live only in the props file (no JSX fallbacks).
  • Resources are Wix-hosted, prop-supplied, or locally bundled.

Source: SKILL.md on GitHub

1 warningtoday4 checks · Risk SAFE
  • Gen Agent Trust Hubtoday

    This skill is a specialized development toolkit for building extensions on the Wix platform. It provides comprehensive instructions for creating dashboard pages, backend APIs, and site plugins using the Wix CLI and SDKs. No malicious patterns were detected; the skill's behaviors, such as dependency management, command execution for builds, and local script execution for code reviews, are entirely consistent with its purpose as a developer productivity tool for the Wix ecosystem.

  • Sockettoday

    1 alert: gptAnomaly

  • Snyktoday

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at dc6f1fa. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated yesterday
compatibility
requires `@wix/cli` >= 1.1.192.

README badge

README badge for wix/skills/wix-app

Builds dashboard pages, modals, plugins, custom widgets, Editor React components, backend APIs, events, service plugins, and data collections for Wix CLI apps. Provides decision logic, API patterns, and validation workflows; scaffolding is owned by the Wix CLI via `wix generate --params`.

Generated from the current SKILL.md.

What extension types does this skill cover?
All Wix CLI app extension types: dashboard pages, modals, plugins, menu plugins, custom element widgets, Editor React components, site plugins, embedded scripts, backend APIs, backend events, service plugins, and data collections.
Does this skill scaffold the extension files for me?
The Wix CLI owns scaffolding via `wix generate --params` for all extension types except Backend API. This skill provides decision logic, API guidance, and business-logic patterns to fill in the generated stubs. Backend API files must be created manually.
What Wix CLI version is required?
The skill requires @wix/cli >= 1.1.192.
Do I need to create a Data Collection extension for app-specific data?
Yes, if you're saving or persisting app-specific data, managing domain entities in a dashboard, or running a service plugin that reads app-configured data. The skill infers this automatically—you don't need to explicitly request it.
Does this skill cover Wix Stores API usage?
Yes. When using any Wix Stores API (products, inventory, orders), the skill requires dual V1/V3 catalog support and references the Stores Versioning guide for module selection and field mapping.

Generated from the current SKILL.md. These answers refresh after source changes.