or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-modals.mdconfirm-modals.mdcontext-modals.mdhook-usage.mdindex.mdprovider-setup.md

hook-usage.mddocs/

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

```