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
and
.
1. - 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',
});
The
must be a unique, static UUID v4 string. Generate a fresh UUID for each extension - do NOT use
or copy UUIDs from examples. Replace
with a freshly generated UUID like
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
.
2. - 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. - Configurable properties:
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()
Use
to access data passed via
in
:
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>;
}
Call
from within the modal extension to close it. Optionally pass data back to the opener.
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 */}
/>
);
}