0
# Context Modals
1
2
Predefined reusable modal components registered with the provider for consistent modal experiences.
3
4
## Capabilities
5
6
### Open Context Modal
7
8
Opens a predefined modal component by key with custom properties.
9
10
```typescript { .api }
11
/**
12
* Opens a predefined context modal by key
13
* @param payload - Modal key, configuration, and inner props
14
* @returns Modal ID for future reference
15
*/
16
function openContextModal<TKey extends MantineModal>(
17
payload: OpenContextModal<Parameters<MantineModals[TKey]>[0]['innerProps']> & { modal: TKey }
18
): string;
19
20
interface OpenContextModal<CustomProps extends Record<string, any> = {}> extends ModalSettings {
21
/** Custom props passed to the modal component */
22
innerProps: CustomProps;
23
}
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import { openContextModal } from "@mantine/modals";
30
31
// Open registered context modal
32
openContextModal({
33
modal: "userProfile",
34
title: "User Profile",
35
innerProps: {
36
userId: "123",
37
editable: true,
38
},
39
});
40
41
// Context modal with custom modal properties
42
openContextModal({
43
modal: "deleteConfirmation",
44
title: "Delete Item",
45
size: "sm",
46
centered: true,
47
innerProps: {
48
itemName: "Important Document",
49
itemType: "document",
50
onConfirm: () => deleteDocument("doc-123"),
51
},
52
});
53
```
54
55
### Update Context Modal
56
57
Updates properties of an existing context modal.
58
59
```typescript { .api }
60
/**
61
* Updates properties of an existing context modal
62
* @param payload - Modal ID and updated properties
63
*/
64
function updateContextModal(
65
payload: { modalId: string } & Partial<OpenContextModal<any>>
66
): void;
67
```
68
69
**Usage Examples:**
70
71
```typescript
72
import { openContextModal, updateContextModal } from "@mantine/modals";
73
74
// Open context modal
75
const modalId = openContextModal({
76
modal: "dataEditor",
77
modalId: "editor-1",
78
title: "Edit Data",
79
innerProps: {
80
data: initialData,
81
readOnly: false,
82
},
83
});
84
85
// Update inner props
86
updateContextModal({
87
modalId: "editor-1",
88
innerProps: {
89
data: updatedData,
90
readOnly: true, // Make read-only
91
},
92
});
93
94
// Update modal properties
95
updateContextModal({
96
modalId: "editor-1",
97
title: "View Data (Read Only)",
98
size: "lg",
99
});
100
```
101
102
### Context Modal Component
103
104
Interface for creating context modal components.
105
106
```typescript { .api }
107
/**
108
* Props interface for context modal components
109
*/
110
interface ContextModalProps<T extends Record<string, any> = {}> {
111
/** Modal context providing access to modal methods */
112
context: ModalsContextProps;
113
/** Custom props passed when opening the modal */
114
innerProps: T;
115
/** Unique modal instance ID */
116
id: string;
117
}
118
```
119
120
**Creating Context Modals:**
121
122
```typescript
123
import { ContextModalProps } from "@mantine/modals";
124
import { Button, Text, TextInput, Stack } from "@mantine/core";
125
126
// User profile modal component
127
interface UserProfileProps {
128
userId: string;
129
editable?: boolean;
130
onSave?: (data: any) => void;
131
}
132
133
const UserProfileModal: React.FC<ContextModalProps<UserProfileProps>> = ({
134
context,
135
id,
136
innerProps,
137
}) => {
138
const [userData, setUserData] = useState(null);
139
const [loading, setLoading] = useState(true);
140
141
useEffect(() => {
142
// Load user data
143
loadUser(innerProps.userId).then((data) => {
144
setUserData(data);
145
setLoading(false);
146
});
147
}, [innerProps.userId]);
148
149
const handleSave = async () => {
150
if (innerProps.onSave) {
151
await innerProps.onSave(userData);
152
}
153
context.closeModal(id);
154
};
155
156
if (loading) {
157
return <Text>Loading user profile...</Text>;
158
}
159
160
return (
161
<Stack>
162
<TextInput
163
label="Name"
164
value={userData.name}
165
disabled={!innerProps.editable}
166
onChange={(e) => setUserData({ ...userData, name: e.target.value })}
167
/>
168
<TextInput
169
label="Email"
170
value={userData.email}
171
disabled={!innerProps.editable}
172
onChange={(e) => setUserData({ ...userData, email: e.target.value })}
173
/>
174
175
{innerProps.editable && (
176
<Button.Group>
177
<Button variant="default" onClick={() => context.closeModal(id)}>
178
Cancel
179
</Button>
180
<Button onClick={handleSave}>
181
Save Changes
182
</Button>
183
</Button.Group>
184
)}
185
186
{!innerProps.editable && (
187
<Button onClick={() => context.closeModal(id)}>
188
Close
189
</Button>
190
)}
191
</Stack>
192
);
193
};
194
```
195
196
### Registration and Type Safety
197
198
Register context modals with the provider and ensure type safety.
199
200
**Provider Registration:**
201
202
```typescript
203
import { ModalsProvider } from "@mantine/modals";
204
205
// Register context modals
206
<ModalsProvider
207
modals={{
208
userProfile: UserProfileModal,
209
deleteConfirmation: DeleteConfirmationModal,
210
dataEditor: DataEditorModal,
211
}}
212
>
213
<App />
214
</ModalsProvider>
215
```
216
217
**Module Augmentation for Type Safety:**
218
219
```typescript
220
// types/modals.ts
221
import { ContextModalProps } from "@mantine/modals";
222
223
declare module "@mantine/modals" {
224
interface MantineModalsOverride {
225
modals: {
226
userProfile: ContextModalProps<{
227
userId: string;
228
editable?: boolean;
229
onSave?: (data: any) => void;
230
}>;
231
deleteConfirmation: ContextModalProps<{
232
itemName: string;
233
itemType: string;
234
onConfirm: () => void;
235
}>;
236
dataEditor: ContextModalProps<{
237
data: any;
238
readOnly?: boolean;
239
onSubmit?: (data: any) => void;
240
}>;
241
};
242
}
243
}
244
```
245
246
### Advanced Context Modal Patterns
247
248
Complex context modal usage patterns and techniques.
249
250
**Dynamic Modal Loading:**
251
252
```typescript
253
// Lazy-loaded context modal
254
const LazyFormModal = lazy(() => import("./FormModal"));
255
256
const DynamicFormModal: React.FC<ContextModalProps<{ formType: string }>> = (props) => {
257
return (
258
<Suspense fallback={<Text>Loading form...</Text>}>
259
<LazyFormModal {...props} />
260
</Suspense>
261
);
262
};
263
264
// Register dynamic modal
265
<ModalsProvider
266
modals={{
267
dynamicForm: DynamicFormModal,
268
}}
269
>
270
<App />
271
</ModalsProvider>
272
```
273
274
**Modal Communication:**
275
276
```typescript
277
// Modal that opens other modals
278
const ParentModal: React.FC<ContextModalProps<{ data: any }>> = ({
279
context,
280
id,
281
innerProps,
282
}) => {
283
const openChildModal = () => {
284
context.openContextModal("childModal", {
285
title: "Child Modal",
286
innerProps: {
287
parentId: id,
288
data: innerProps.data,
289
onComplete: (result) => {
290
// Handle child modal completion
291
updateContextModal({
292
modalId: id,
293
innerProps: {
294
...innerProps,
295
data: { ...innerProps.data, ...result },
296
},
297
});
298
},
299
},
300
});
301
};
302
303
return (
304
<div>
305
<Text>Parent Modal Content</Text>
306
<Button onClick={openChildModal}>Open Child Modal</Button>
307
<Button onClick={() => context.closeModal(id)}>Close</Button>
308
</div>
309
);
310
};
311
```
312
313
**Context Modal with State Synchronization:**
314
315
```typescript
316
// Modal that syncs with external state
317
const SyncedModal: React.FC<ContextModalProps<{
318
storeId: string;
319
onStateChange: (state: any) => void;
320
}>> = ({ context, id, innerProps }) => {
321
const [localState, setLocalState] = useState({});
322
323
// Sync changes back to parent
324
useEffect(() => {
325
innerProps.onStateChange?.(localState);
326
}, [localState]);
327
328
// Listen for external updates
329
useEffect(() => {
330
const unsubscribe = subscribeToStore(innerProps.storeId, (newState) => {
331
setLocalState(newState);
332
});
333
return unsubscribe;
334
}, [innerProps.storeId]);
335
336
return (
337
<div>
338
{/* Modal content that updates localState */}
339
</div>
340
);
341
};
342
```