0
# Hook-based Usage
1
2
React hook providing access to modal context methods for component-based modal management.
3
4
## Capabilities
5
6
### useModals Hook
7
8
React hook that provides access to modal context and methods for imperative modal control within components.
9
10
```typescript { .api }
11
/**
12
* Hook to access modal context and methods
13
* @returns Modal context with all modal management methods
14
* @throws Error if called outside ModalsProvider
15
*/
16
function useModals(): ModalsContextProps;
17
18
interface ModalsContextProps {
19
/** Default modal properties applied to all modals */
20
modalProps: ModalSettings;
21
/** Array of currently open modals */
22
modals: ModalState[];
23
/** Open a content modal */
24
openModal: (props: ModalSettings) => string;
25
/** Open a confirmation modal */
26
openConfirmModal: (props: OpenConfirmModal) => string;
27
/** Open a context modal */
28
openContextModal: <TKey extends MantineModal>(
29
modal: TKey,
30
props: OpenContextModal<Parameters<MantineModals[TKey]>[0]['innerProps']>
31
) => string;
32
/** Close a specific modal */
33
closeModal: (id: string, canceled?: boolean) => void;
34
/** Close a context modal */
35
closeContextModal: <TKey extends MantineModal>(id: TKey, canceled?: boolean) => void;
36
/** Close all modals */
37
closeAll: () => void;
38
/** Update modal properties */
39
updateModal: (payload: { modalId: string } & Partial<OpenConfirmModal>) => void;
40
/** Update context modal properties */
41
updateContextModal: (payload: { modalId: string } & Partial<OpenContextModal<any>>) => void;
42
}
43
```
44
45
**Basic Usage:**
46
47
```typescript
48
import { useModals } from "@mantine/modals";
49
import { Button, Text } from "@mantine/core";
50
51
function MyComponent() {
52
const modals = useModals();
53
54
const showInfoModal = () => {
55
modals.openModal({
56
title: "Information",
57
children: <Text>This is some important information.</Text>,
58
});
59
};
60
61
const showConfirmModal = () => {
62
modals.openConfirmModal({
63
title: "Confirm Action",
64
children: <Text>Are you sure you want to proceed?</Text>,
65
labels: { confirm: "Yes", cancel: "No" },
66
onConfirm: () => console.log("Confirmed"),
67
onCancel: () => console.log("Cancelled"),
68
});
69
};
70
71
return (
72
<div>
73
<Button onClick={showInfoModal}>Show Info</Button>
74
<Button onClick={showConfirmModal}>Show Confirm</Button>
75
</div>
76
);
77
}
78
```
79
80
### Modal State Access
81
82
Access current modal state information through the hook.
83
84
```typescript { .api }
85
/**
86
* Current modal state
87
*/
88
interface ModalState {
89
/** Unique modal ID */
90
id: string;
91
/** Modal properties */
92
props: ModalSettings | OpenConfirmModal | OpenContextModal;
93
/** Modal type */
94
type: 'content' | 'confirm' | 'context';
95
/** Context modal key (for context modals only) */
96
ctx?: string;
97
}
98
```
99
100
**Usage Examples:**
101
102
```typescript
103
import { useModals } from "@mantine/modals";
104
105
function ModalStatusComponent() {
106
const modals = useModals();
107
108
return (
109
<div>
110
<Text>Open modals: {modals.modals.length}</Text>
111
{modals.modals.length > 0 && (
112
<div>
113
<Text>Current modals:</Text>
114
{modals.modals.map((modal) => (
115
<Text key={modal.id} size="sm">
116
- {modal.id} ({modal.type})
117
</Text>
118
))}
119
<Button onClick={modals.closeAll}>Close All</Button>
120
</div>
121
)}
122
</div>
123
);
124
}
125
```
126
127
### Component-Based Modal Management
128
129
Using the hook for complex modal workflows within components.
130
131
**Form Modal Example:**
132
133
```typescript
134
import { useModals } from "@mantine/modals";
135
import { useState } from "react";
136
import { Button, TextInput, Stack } from "@mantine/core";
137
138
function EditUserComponent({ user }) {
139
const modals = useModals();
140
const [formData, setFormData] = useState(user);
141
142
const handleEdit = () => {
143
const modalId = modals.openModal({
144
title: "Edit User",
145
size: "md",
146
children: (
147
<UserEditForm
148
data={formData}
149
onSave={(data) => {
150
setFormData(data);
151
modals.closeModal(modalId);
152
saveUser(data);
153
}}
154
onCancel={() => modals.closeModal(modalId)}
155
/>
156
),
157
});
158
};
159
160
const handleDelete = () => {
161
modals.openConfirmModal({
162
title: "Delete User",
163
children: <Text>Are you sure you want to delete this user?</Text>,
164
labels: { confirm: "Delete", cancel: "Cancel" },
165
confirmProps: { color: "red" },
166
onConfirm: () => deleteUser(user.id),
167
});
168
};
169
170
return (
171
<div>
172
<Button onClick={handleEdit}>Edit</Button>
173
<Button color="red" onClick={handleDelete}>Delete</Button>
174
</div>
175
);
176
}
177
```
178
179
**Multi-Step Workflow:**
180
181
```typescript
182
import { useModals } from "@mantine/modals";
183
184
function MultiStepWorkflow() {
185
const modals = useModals();
186
187
const startWorkflow = () => {
188
// Step 1: Choose action
189
const step1Id = modals.openModal({
190
title: "Step 1: Choose Action",
191
children: (
192
<Stack>
193
<Text>What would you like to do?</Text>
194
<Button onClick={() => {
195
modals.closeModal(step1Id);
196
showStep2("create");
197
}}>
198
Create New
199
</Button>
200
<Button onClick={() => {
201
modals.closeModal(step1Id);
202
showStep2("import");
203
}}>
204
Import Existing
205
</Button>
206
</Stack>
207
),
208
});
209
};
210
211
const showStep2 = (action: string) => {
212
const step2Id = modals.openModal({
213
title: `Step 2: ${action === "create" ? "Create" : "Import"}`,
214
children: (
215
<Stack>
216
<Text>Configure your {action} settings:</Text>
217
{/* Form components based on action */}
218
<Button onClick={() => {
219
modals.closeModal(step2Id);
220
showStep3(action);
221
}}>
222
Next
223
</Button>
224
<Button variant="default" onClick={() => {
225
modals.closeModal(step2Id);
226
startWorkflow(); // Go back to step 1
227
}}>
228
Back
229
</Button>
230
</Stack>
231
),
232
});
233
};
234
235
const showStep3 = (action: string) => {
236
modals.openConfirmModal({
237
title: "Step 3: Confirm",
238
children: <Text>Ready to {action}? This action cannot be undone.</Text>,
239
labels: { confirm: "Proceed", cancel: "Cancel" },
240
onConfirm: () => performAction(action),
241
});
242
};
243
244
return <Button onClick={startWorkflow}>Start Workflow</Button>;
245
}
246
```
247
248
### Dynamic Modal Updates
249
250
Using the hook to dynamically update modals based on component state.
251
252
```typescript
253
import { useModals } from "@mantine/modals";
254
import { useState, useEffect } from "react";
255
256
function DynamicModalComponent() {
257
const modals = useModals();
258
const [progress, setProgress] = useState(0);
259
const [modalId, setModalId] = useState<string | null>(null);
260
261
const startProcess = () => {
262
const id = modals.openModal({
263
title: "Processing...",
264
children: <Text>Starting process...</Text>,
265
closeOnClickOutside: false,
266
closeOnEscape: false,
267
});
268
setModalId(id);
269
setProgress(0);
270
};
271
272
// Update modal based on progress
273
useEffect(() => {
274
if (modalId && progress > 0) {
275
modals.updateModal({
276
modalId,
277
title: `Processing... ${progress}%`,
278
children: (
279
<div>
280
<Text>Progress: {progress}%</Text>
281
<div style={{
282
width: "100%",
283
height: "10px",
284
backgroundColor: "#f0f0f0",
285
borderRadius: "5px"
286
}}>
287
<div style={{
288
width: `${progress}%`,
289
height: "100%",
290
backgroundColor: "#007bff",
291
borderRadius: "5px",
292
transition: "width 0.3s ease",
293
}} />
294
</div>
295
</div>
296
),
297
});
298
299
if (progress >= 100) {
300
setTimeout(() => {
301
modals.updateModal({
302
modalId,
303
title: "Complete!",
304
children: (
305
<div>
306
<Text c="green">Process completed successfully!</Text>
307
<Button
308
mt="md"
309
onClick={() => {
310
modals.closeModal(modalId);
311
setModalId(null);
312
setProgress(0);
313
}}
314
>
315
Close
316
</Button>
317
</div>
318
),
319
});
320
}, 500);
321
}
322
}
323
}, [progress, modalId]);
324
325
// Simulate progress
326
useEffect(() => {
327
if (modalId && progress < 100) {
328
const timer = setTimeout(() => {
329
setProgress(prev => Math.min(prev + 10, 100));
330
}, 500);
331
return () => clearTimeout(timer);
332
}
333
}, [progress, modalId]);
334
335
return <Button onClick={startProcess}>Start Process</Button>;
336
}
337
```
338
339
### Error Handling
340
341
Proper error handling when using the hook.
342
343
```typescript
344
import { useModals } from "@mantine/modals";
345
346
function SafeModalComponent() {
347
const modals = useModals();
348
349
const handleAsyncAction = async () => {
350
const modalId = modals.openModal({
351
title: "Loading...",
352
children: <Text>Please wait...</Text>,
353
});
354
355
try {
356
const result = await performAsyncOperation();
357
358
modals.updateModal({
359
modalId,
360
title: "Success",
361
children: (
362
<div>
363
<Text c="green">Operation completed successfully!</Text>
364
<Button mt="md" onClick={() => modals.closeModal(modalId)}>
365
OK
366
</Button>
367
</div>
368
),
369
});
370
} catch (error) {
371
modals.updateModal({
372
modalId,
373
title: "Error",
374
children: (
375
<div>
376
<Text c="red">Operation failed: {error.message}</Text>
377
<Button.Group mt="md">
378
<Button variant="default" onClick={() => modals.closeModal(modalId)}>
379
Cancel
380
</Button>
381
<Button onClick={() => {
382
modals.closeModal(modalId);
383
handleAsyncAction(); // Retry
384
}}>
385
Retry
386
</Button>
387
</Button.Group>
388
</div>
389
),
390
});
391
}
392
};
393
394
return <Button onClick={handleAsyncAction}>Start Async Action</Button>;
395
}
396
397
// Component that handles hook errors
398
function ModalProvider({ children }) {
399
try {
400
return (
401
<ModalsProvider>
402
{children}
403
</ModalsProvider>
404
);
405
} catch (error) {
406
console.error("Modal provider error:", error);
407
return <div>Modal system unavailable</div>;
408
}
409
}
410
```