wix-cli-site-plugin

Use when building interactive components for predefined slots in Wix business solutions. Triggers include site plugin, slot, Wix app integration, plugin explorer, business solution extension.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "wix-cli-site-plugin" with this command: npx skills add wix/skills/wix-skills-wix-cli-site-plugin

Wix Site Plugin Builder

Creates site plugin extensions for Wix CLI applications. Site plugins are custom elements that integrate into predefined slots within Wix business solutions (like Wix Stores, Wix Bookings, Wix eCommerce), extending their functionality and user experience.

Site owners can place site plugins into UI slots using the plugin explorer in Wix editors.

Quick Start Checklist

Follow these steps in order when creating a site plugin:

  1. Create plugin folder: src/extensions/site/plugins/<plugin-name>/
  2. Create <plugin-name>.tsx extending HTMLElement with observedAttributes
  3. Create <plugin-name>.panel.tsx with WDS components and widget.getProp/setProp
  4. Create <plugin-name>.extension.ts with extensions.sitePlugin() and unique UUID
  5. Update src/extensions.ts to import and use the new extension

Architecture

Site plugins consist of three required files:

1. Plugin Component (<plugin-name>.tsx)

Custom element component that renders in the slot using native HTMLElement:

  • Extend HTMLElement class
  • Define observedAttributes for reactive properties
  • Implement connectedCallback() and attributeChangedCallback() for rendering
  • Use inline styles via template strings
  • Attributes use kebab-case (e.g., display-name)

2. Settings Panel (<plugin-name>.panel.tsx)

Settings panel shown in the Wix Editor sidebar:

  • Uses Wix Design System (@wix/design-system) components — see wds-docs for component reference
  • Manages plugin properties via @wix/editor widget API
  • Loads initial values with widget.getProp('kebab-case-name')
  • Updates properties with widget.setProp('kebab-case-name', value)
  • Widget properties are bound to custom element attributes — any property change automatically updates the corresponding attribute
  • Wrapped in WixDesignSystemProvider > SidePanel > SidePanel.Content

3. Extension Configuration (<plugin-name>.extension.ts)

Defines the plugin's placement configuration:

  • Specifies which slots the plugin can be added to
  • Configures auto-add behavior on app installation
  • Sets the tag name and file paths

Plugin Component Pattern

Site plugins use native HTMLElement custom elements:

// my-site-plugin.tsx
class MyElement extends HTMLElement {
  static get observedAttributes() {
    return ['display-name'];
  }

  constructor() {
    super();
  }

  connectedCallback() {
    this.render();
  }

  attributeChangedCallback() {
    this.render();
  }

  render() {
    const displayName = this.getAttribute('display-name') || "Your Plugin's Title";

    this.innerHTML = `
      <div style="font-size: 16px; padding: 16px; border: 1px solid #ccc; border-radius: 8px; margin: 16px;">
        <h2>${displayName}</h2>
        <hr />
        <p>
          This is a Site Plugin generated by Wix CLI.<br />
          Edit your element's code to change this text.
        </p>
      </div>
    `;
  }
}

export default MyElement;

Key Points:

  • Extend HTMLElement class directly
  • Define observedAttributes static getter to list reactive attributes
  • Attributes use kebab-case (e.g., display-name, bg-color)
  • Implement connectedCallback() for initial render
  • Implement attributeChangedCallback() to re-render when attributes change
  • Use inline styles via template strings
  • Use this.getAttribute('attribute-name') to read attribute values
  • Wix handles define() for you — do NOT call customElements.define() in your code

Settings Panel Pattern

// my-site-plugin.panel.tsx
import React, { type FC, useState, useEffect, useCallback } from 'react';
import { widget } from '@wix/editor';
import {
  SidePanel,
  WixDesignSystemProvider,
  Input,
  FormField,
} from '@wix/design-system';
import '@wix/design-system/styles.global.css';

const Panel: FC = () => {
  const [displayName, setDisplayName] = useState<string>('');

  useEffect(() => {
    widget.getProp('display-name')
      .then(displayName => setDisplayName(displayName || "Your Plugin's Title"))
      .catch(error => console.error('Failed to fetch display-name:', error));
  }, [setDisplayName]);

  const handleDisplayNameChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
    const newDisplayName = event.target.value;
    setDisplayName(newDisplayName);
    widget.setProp('display-name', newDisplayName);
  }, [setDisplayName]);

  return (
    <WixDesignSystemProvider>
      <SidePanel width="300" height="100vh">
        <SidePanel.Content noPadding stretchVertically>
          <SidePanel.Field>
            <FormField label="Display Name">
              <Input
                type="text"
                value={displayName}
                onChange={handleDisplayNameChange}
                aria-label="Display Name"
              />
            </FormField>
          </SidePanel.Field>
        </SidePanel.Content>
      </SidePanel>
    </WixDesignSystemProvider>
  );
};

export default Panel;

Key Points:

  • Prop names in widget.getProp() and widget.setProp() use kebab-case (e.g., "display-name")
  • Always update both local state AND widget prop in onChange handlers
  • Widget properties are bound to custom element attributes — changes automatically update the corresponding attribute
  • Wrap content in WixDesignSystemProvider > SidePanel > SidePanel.Content
  • Use WDS components from @wix/design-system
  • Import @wix/design-system/styles.global.css for styles
  • Include aria-label for accessibility

Color & Font Picker Fields

Site plugin settings panels can use inputs.selectColor() and inputs.selectFont() from @wix/editor to open the native Wix Editor color and font picker dialogs.

ColorPickerField

Opens the Wix color picker with theme colors, gradients, and more — NOT a basic HTML <input type="color">.

import React, { type FC } from 'react';
import { inputs } from '@wix/editor';
import { FormField, Box, FillPreview, SidePanel } from '@wix/design-system';

interface ColorPickerFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
}

export const ColorPickerField: FC<ColorPickerFieldProps> = ({
  label,
  value,
  onChange,
}) => (
  <SidePanel.Field>
    <FormField label={label}>
      <Box width="30px" height="30px">
        <FillPreview
          fill={value}
          onClick={() => inputs.selectColor(value, { onChange: (val) => { if (val) onChange(val); } })}
        />
      </Box>
    </FormField>
  </SidePanel.Field>
);

FontPickerField

Opens the Wix font picker with font family, size, bold, italic, and other typography features.

import React, { type FC } from 'react';
import { inputs } from '@wix/editor';
import { FormField, Button, Text, SidePanel } from '@wix/design-system';

interface FontValue {
  font: string;
  textDecoration: string;
}

interface FontPickerFieldProps {
  label: string;
  value: FontValue;
  onChange: (value: FontValue) => void;
}

export const FontPickerField: FC<FontPickerFieldProps> = ({
  label,
  value,
  onChange,
}) => (
  <SidePanel.Field>
    <FormField label={label}>
      <Button
        size="small"
        priority="secondary"
        onClick={() => inputs.selectFont(value, { onChange: (val) => onChange({ font: val.font, textDecoration: val.textDecoration || "" }) })}
        fullWidth
      >
        <Text size="small" ellipsis>Change Font</Text>
      </Button>
    </FormField>
  </SidePanel.Field>
);

Important:

  • Always use inputs.selectColor() from @wix/editor with FillPreview — do NOT use <Input type="color">
  • Always use inputs.selectFont() from @wix/editor with the callback pattern inputs.selectFont(value, { onChange })
  • Import inputs from @wix/editor (not from @wix/sdk)

Attribute Naming Convention

Site plugins use kebab-case consistently for HTML attributes:

FileConventionExample
<plugin>.tsx (getAttribute)kebab-casethis.getAttribute('display-name')
<plugin>.tsx (observedAttributes)kebab-case['display-name', 'bg-color']
<plugin>.panel.tsx (widget API)kebab-casewidget.getProp('display-name')

Output Structure

Site plugins live under src/extensions/site/plugins. Each plugin has its own folder with files named after the plugin.

src/extensions/site/plugins/
└── {plugin-name}/
    ├── {plugin-name}.tsx           # Main plugin component (HTMLElement)
    ├── {plugin-name}.panel.tsx     # Settings panel component
    └── {plugin-name}.extension.ts  # Extension registration
public/
└── {plugin-name}-logo.svg          # Plugin logo (optional)

References

TopicReference
Complete ExamplesEXAMPLES.md
Slots (App IDs, multiple placements, finding slots)SLOTS.md
WDS Componentswds-docs

Available Slots

Site plugins integrate into predefined slots in Wix business solutions. Each slot is identified by:

  • appDefinitionId: The ID of the Wix app (e.g., Stores, Bookings)
  • widgetId: The ID of the page containing the slot
  • slotId: The specific slot identifier

Common placement areas include product pages (Wix Stores), checkout and side cart (Wix eCommerce), booking pages (Wix Bookings), service pages, event pages, and blog post pages.

For supported pages, common Wix App IDs, and how to find slot IDs, see SLOTS.md.

Extension Registration

Extension registration is MANDATORY and has TWO required steps.

Step 1: Create Plugin-Specific Extension File

Each site plugin requires an extension file in its folder:

// my-site-plugin.extension.ts
import { extensions } from '@wix/astro/builders';

export default extensions.sitePlugin({
  id: '{{GENERATE_UUID}}',
  name: 'My Site Plugin',
  marketData: {
    name: 'My Site Plugin',
    description: 'Marketing Description',
    logoUrl: '{{BASE_URL}}/my-site-plugin-logo.svg',
  },
  placements: [{
    appDefinitionId: 'a0c68605-c2e7-4c8d-9ea1-767f9770e087',
    widgetId: '6a25b678-53ec-4b37-a190-65fcd1ca1a63',
    slotId: 'product-page-details-6',
  }],
  installation: { autoAdd: true },
  tagName: 'my-site-plugin',
  element: './extensions/site/plugins/my-site-plugin/my-site-plugin.tsx',
  settings: './extensions/site/plugins/my-site-plugin/my-site-plugin.panel.tsx',
});

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. Replace {{GENERATE_UUID}} with a freshly generated UUID like "95a28afd-7df1-4e09-9ec1-ce710b0389a0".

PropertyTypeDescription
idstringUnique static UUID v4 (generate fresh)
namestringInternal name for the plugin
marketData.namestringDisplay name in plugin explorer and app dashboard
marketData.descriptionstringDescription shown in plugin explorer and app dashboard
marketData.logoUrlstringPath to logo file ({{BASE_URL}} resolves to public folder)
placementsarrayArray of slot placements where plugin can be added
placements.appDefinitionIdstringID of the Wix app containing the slot
placements.widgetIdstringID of the page containing the slot
placements.slotIdstringID of the specific slot
installation.autoAddbooleanWhether to auto-add plugin to slots on app installation
tagNamestringHTML custom element tag (kebab-case, must contain a hyphen)
elementstringRelative path to plugin component
settingsstringRelative path to settings panel component

Step 2: Register in Main Extensions File

CRITICAL: After creating the plugin-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 plugin will not be available in the plugin explorer.

Checkout Plugins

If you are building a plugin for the checkout page, it may not support automatic addition upon installation. You must create a dashboard page to provide users with a way to add the plugin to their site. See EXAMPLES.md for the dashboard page pattern.

Examples

For complete examples with all three required files (plugin component, settings panel, extension configuration), see EXAMPLES.md.

Example use cases:

  • Best Seller Badge - Customizable badge on product pages with text and color settings
  • Booking Confirmation - Custom confirmation message for booking pages
  • Product Reviews Summary - Star rating and review count display
  • Data-Driven Plugin - Plugin with Wix Data API integration and editor environment handling

Best Practices

Implementation Guidelines

  • Use inline styles - CSS imports are not supported in custom elements
  • Handle editor environment - Show placeholders when in editor mode for data-dependent plugins
  • Do not call define() - Wix handles customElements.define() for you automatically
  • Validate all input - Check required props are present
  • Follow naming conventions - kebab-case for all attributes and widget API
  • Keep plugins focused - Each plugin should do one thing well
  • Test in multiple slots - If supporting multiple placements, test each one
  • Support both Stores versions - Include placements for both old and new Wix Stores product pages for maximum compatibility

Editor Sandboxing

Site plugins are sandboxed when rendered in the editor. This means they're treated as if they come from a different domain, which impacts access to browser storage APIs.

Restricted APIs in the editor:

  • localStorage and sessionStorage (Web Storage API)
  • document.cookie (Cookie Store API)
  • IndexedDB API
  • Cache API

How to handle sandboxing:

Use the viewMode() function from @wix/site-window to check the current mode before accessing restricted APIs:

import { window as wixWindow } from '@wix/site-window';

const viewMode = await wixWindow.viewMode();

if (viewMode === 'Site') {
  const item = localStorage.getItem('myKey');
} else {
  // Mock storage or modify API usage for editor mode
}

Using Wix SDK Modules in Site Plugins

Site plugins can import and use Wix SDK modules directly — you do NOT need createClient(). The Wix runtime provides the client context automatically.

// ✅ CORRECT — Import SDK modules directly
import { items } from "@wix/data";
import { currentCart } from "@wix/ecom";
import { products } from "@wix/stores";

class MyPlugin extends HTMLElement {
  async loadData() {
    // Call SDK methods directly — no createClient needed
    const result = await items.query("MyCollection").find();
    const cart = await currentCart.getCurrentCart();
    const productList = await products.queryProducts().limit(10).find();
  }
}
// ❌ WRONG — Do NOT use createClient in site plugins
import { createClient } from "@wix/sdk";
const wixClient = createClient({ modules: { items, products } });
await wixClient.items.query(...); // Wrong — API surface differs through client

Performance Considerations

  • Keep bundle size small - plugins load on user-facing pages
  • Avoid heavy computations on initial render
  • Lazy load data when possible
  • Use efficient re-rendering patterns

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

wix-cli-embedded-script

No summary provided by upstream source.

Repository SourceNeeds Review
91-wix
Coding

wix-cli-backend-api

No summary provided by upstream source.

Repository SourceNeeds Review
91-wix
Coding

wix-cli-dashboard-modal

No summary provided by upstream source.

Repository SourceNeeds Review
91-wix
Coding

wix-cli-service-plugin

No summary provided by upstream source.

Repository SourceNeeds Review
91-wix