AgentSkillsCN

wix-cli-dashboard-modal

在为Wix仪表板添加弹出式表单、确认框,或详情视图时,或在仪表板页面间创建可复用的对话框组件,或在叠加层中展示特定情境下的信息,或从仪表板页面打开模态窗口,又或在仪表板页面与模态窗口之间传递数据时,此技能可助你轻松实现这些功能——但请勿用于静态内容(建议改用仪表板页面)或面向网站的UI(建议改用网站小部件或嵌入式脚本)。

SKILL.md
--- frontmatter
name: wix-cli-dashboard-modal
description: Use when adding popup forms, confirmations, or detail views to Wix dashboards; creating reusable dialog components across dashboard pages; showing context-specific information in overlays; opening modals from dashboard pages; or passing data between dashboard pages and modals. Do NOT use for static content (use dashboard pages instead) or site-facing UI (use site widgets/embedded scripts).
compatibility: Requires Wix CLI development environment.

Overview

Dashboard modals are popup dialogs triggered from dashboard pages or plugins. They consist of three files and use the Dashboard SDK for lifecycle control via openModal() and closeModal().

Quick Reference

TaskMethodExample
Create modalCreate 3 files in src/dashboard/modals/<folder>/See File Structure below
Open modaldashboard.openModal()openModal({ modalId: "modal-id" })
Pass data to modalparams in openModal()params: { userId: "123" }
Read data in modalobserveState()dashboard.observeState((state) => { ... })
Close modaldashboard.closeModal()closeModal()
Return data to parentPass data to closeModal()closeModal({ ... })
Wait for modal closemodalClosed Promiseconst { modalClosed } = openModal(...);

File Structure

Create three files in src/dashboard/modals/<folder-name>/:

  1. extensions.ts - Builder configuration with modal ID, title, dimensions, component path
  2. <modal-name>.tsx - React component rendering modal content
  3. <modal-name>.config.ts - Configurable modal properties (title, width, height)

Implementation

Creating a Modal

Create the three required files:

1. extensions.ts - Modal builder configuration:

typescript
import { extensions } from '@wix/astro/builders';
import config from './<modal-name>.config.ts';

export default extensions.dashboardModal({
  id: "{{GENERATE_UUID}}",
  title: config.title,
  width: config.width,
  height: config.height,
  component: './extensions/dashboard/modals/<modal-name>/<modal-name>.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 "a1b2c3d4-e5f6-7890-abcd-ef1234567890".

Builder fields:

FieldTypeDescription
idstringUnique modal ID (GUID). Used with openModal()
titlestringModal title shown in project dashboard
widthnumberInitial width while loading
heightnumberInitial height while loading
componentstringPath to the modal content .tsx file

2. <modal-name>.tsx - Modal content component:

typescript
import type { FC } from 'react';
import { dashboard } from '@wix/dashboard';
import {
  WixDesignSystemProvider,
  Text,
  Box,
  CustomModalLayout,
} from '@wix/design-system';
import '@wix/design-system/styles.global.css';
import config from './<modal-name>.config.ts';

const { width, height, title } = config;

// To open your modal, call `openModal` with your modal id.
// e.g.
// import { dashboard } from '@wix/dashboard';
// function MyComponent() {
//   return <button onClick={() => dashboard.openModal({ modalId: '8ef4d434-9c80-44f5-a3f5-6f15f3a34be7' })}>Open Modal</button>;
// }
const Modal: FC = () => {
  return (
    <WixDesignSystemProvider features={{ newColorsBranding: true }}>
      <CustomModalLayout
        width={width}
        maxHeight={height}
        primaryButtonText="Save"
        secondaryButtonText="Cancel"
        primaryButtonOnClick={() => dashboard.closeModal()}
        secondaryButtonOnClick={() => dashboard.closeModal()}
        title={title}
        subtitle="Edit this file to customize your modal"
        content={
          <Box direction="vertical" align="center">
            <Text>Wix CLI Modal</Text>
          </Box>
        }
      />
    </WixDesignSystemProvider>
  );
};

export default Modal;

3. <modal-name>.config.ts - Configurable properties:

typescript
export default {
  title: "My Modal",
  width: 600,
  height: 400,
};

Then register in src/extensions.ts:

typescript
import { dashboardmodalYourModal } from './dashboard/modals/<modal-name>/extensions.ts';

export default app()
  .use(dashboardmodalYourModal)
  // ... other extensions

Opening a Modal

typescript
import { dashboard } from "@wix/dashboard";

// Simple open
const result = await dashboard.openModal({
  modalId: "your-modal-id", // From .extension.ts id field
});

// Pass data to modal via params
const result = await dashboard.openModal({
  modalId: "your-modal-id",
  params: {
    userId: user.id,
    itemData: complexObject, // Objects are passed directly, no encoding needed
  },
});

// Get notified when the modal is closed
const { modalClosed } = dashboard.openModal({
  modalId: "your-modal-id",
});
const result = await modalClosed; // Resolves with data from closeModal()

Receiving Data in Modal

Use observeState() to access data passed via params in openModal():

typescript
import { dashboard } from "@wix/dashboard";
import { useEffect, useState } from "react";

function MyModal() {
  const [modalData, setModalData] = useState<{ userId?: string; itemData?: any }>({});

  useEffect(() => {
    dashboard.observeState((state) => {
      // Access custom data passed through openModal params
      if (state.userId) {
        setModalData({
          userId: state.userId,
          itemData: state.itemData,
        });
      }
    });
  }, []);

  return <div>User ID: {modalData.userId}</div>;
}

Closing Modal

Call closeModal() from within the modal extension to close it. Optionally pass data back to the opener.

typescript
import { dashboard } from "@wix/dashboard";

// Close without returning data
dashboard.closeModal();

// Close with custom return data
dashboard.closeModal({ saved: true, itemId: "123" });
ParameterTypeDescription
closeDataSerializable (optional)Data to pass back to the modal opener. Must be cloneable via structured clone algorithm - no function callbacks.

Returns: void

Customizing Modal

Edit .config.ts for organized settings:

typescript
export default {
  title: 'User Settings',
  width: 600,
  height: 500,
}

Import in .tsx:

typescript
import config from './modal.config.ts';

export default function MyModal() {
  return (
    <CustomModalLayout
      title={config.title}
      // ... rest of component
    />
  );
}

Common Mistakes

MistakeFix
Can't find modal IDCheck .extension.ts file's id field
Forgetting to register in extensions.tsImport and .use() the modal
Using extensionId instead of modalIdUse modalId in openModal()
Can't access params in modalUse dashboard.observeState() to read passed data
Modal won't closeUse dashboard.closeModal() from @wix/dashboard

Real-World Example

typescript
// Dashboard Page: Opening edit modal
const handleEdit = async (item: Item) => {
  dashboard.openModal({
    modalId: "edit-item-modal-guid",
    params: {
      itemId: item._id,
      item: item, // Objects passed directly via params
    },
  });
};

// Modal: Receiving and saving data
export default function ItemEditModal() {
  const [formData, setFormData] = useState<Item | null>(null);

  useEffect(() => {
    dashboard.observeState((state) => {
      if (state.item) {
        setFormData(state.item);
      }
    });
  }, []);

  const handleSave = async () => {
    // Save logic
    dashboard.showToast({ message: "Saved!", type: "success" });
    dashboard.closeModal();
  };

  return (
    <CustomModalLayout
      title="Edit Item"
      primaryButtonText="Save"
      onCloseButtonClick={() => dashboard.closeModal()}
      primaryButtonOnClick={handleSave}
      content={/* form fields */}
    />
  );
}

Verification

After implementation, use wix-cli-app-validation to validate TypeScript compilation, build, preview, and runtime behavior.