or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connect.mdindex.mdmachine.md

index.mddocs/

0

# Zag.js Dialog

1

2

Zag.js Dialog provides a headless, framework-agnostic dialog (modal) component implemented as a finite state machine. It delivers accessible dialog functionality following WAI-ARIA authoring practices, with complete keyboard interactions, focus management, and ARIA roles/attributes handled automatically.

3

4

## Package Information

5

6

- **Package Name**: @zag-js/dialog

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @zag-js/dialog`

10

11

## Core Imports

12

13

```typescript

14

import { machine, connect, anatomy, props, splitProps } from "@zag-js/dialog";

15

import type { Api, Props, Service, ElementIds, OpenChangeDetails } from "@zag-js/dialog";

16

import type { FocusOutsideEvent, InteractOutsideEvent, PointerDownOutsideEvent } from "@zag-js/dialog";

17

```

18

19

For CommonJS:

20

21

```javascript

22

const { machine, connect, anatomy, props, splitProps } = require("@zag-js/dialog");

23

```

24

25

## Basic Usage

26

27

```typescript

28

import { machine, connect } from "@zag-js/dialog";

29

import { normalizeProps } from "@zag-js/react"; // or your framework adapter

30

31

function MyDialog() {

32

// Create machine instance

33

const [state, send] = useMachine(

34

machine({

35

id: "dialog-1",

36

onOpenChange: (details) => {

37

console.log("Dialog open:", details.open);

38

},

39

})

40

);

41

42

// Connect machine to UI

43

const api = connect(state, normalizeProps);

44

45

return (

46

<div>

47

<button {...api.getTriggerProps()}>Open Dialog</button>

48

49

{api.open && (

50

<div {...api.getPositionerProps()}>

51

<div {...api.getBackdropProps()} />

52

<div {...api.getContentProps()}>

53

<h2 {...api.getTitleProps()}>Dialog Title</h2>

54

<p {...api.getDescriptionProps()}>Dialog content goes here</p>

55

<button {...api.getCloseTriggerProps()}>Close</button>

56

</div>

57

</div>

58

)}

59

</div>

60

);

61

}

62

```

63

64

## Architecture

65

66

Zag.js Dialog is built around several key components:

67

68

- **State Machine**: Core logic implemented as a finite state machine with states (open/closed), events, effects, and actions

69

- **Connect API**: Framework-agnostic connection layer that provides prop functions for UI elements

70

- **Anatomy System**: Structured component parts with consistent naming and behavior

71

- **Accessibility Layer**: Built-in ARIA roles, keyboard interactions, and focus management

72

- **Framework Adapters**: Integration with React, Vue, Solid, Svelte through separate adapter packages

73

74

## Capabilities

75

76

### Dialog State Machine

77

78

Core state machine that manages dialog open/closed states, handles events, and orchestrates all dialog behaviors including accessibility features.

79

80

```typescript { .api }

81

function machine(props: Props): Machine;

82

83

interface Machine extends StateMachine<DialogSchema> {

84

state: "open" | "closed";

85

send: (event: MachineEvent) => void;

86

}

87

88

interface MachineEvent {

89

type: "OPEN" | "CLOSE" | "TOGGLE" | "CONTROLLED.OPEN" | "CONTROLLED.CLOSE";

90

}

91

```

92

93

[Dialog State Machine](./machine.md)

94

95

### API Connection

96

97

Connection layer that transforms state machine into framework-agnostic prop functions for UI elements, providing complete accessibility and interaction handling.

98

99

```typescript { .api }

100

function connect<T extends PropTypes>(

101

service: Service<DialogSchema>,

102

normalize: NormalizeProps<T>

103

): Api<T>;

104

105

interface Api<T extends PropTypes> {

106

open: boolean;

107

setOpen: (open: boolean) => void;

108

getTriggerProps: () => T["button"];

109

getBackdropProps: () => T["element"];

110

getPositionerProps: () => T["element"];

111

getContentProps: () => T["element"];

112

getTitleProps: () => T["element"];

113

getDescriptionProps: () => T["element"];

114

getCloseTriggerProps: () => T["button"];

115

}

116

```

117

118

[API Connection Methods](./connect.md)

119

120

### Component Anatomy

121

122

Anatomical structure defining the dialog's component parts with consistent naming and CSS class generation.

123

124

```typescript { .api }

125

interface Anatomy {

126

trigger: AnatomyPart;

127

backdrop: AnatomyPart;

128

positioner: AnatomyPart;

129

content: AnatomyPart;

130

title: AnatomyPart;

131

description: AnatomyPart;

132

closeTrigger: AnatomyPart;

133

}

134

135

const anatomy: Anatomy;

136

```

137

138

### Event Types

139

140

Event types for dismissible interactions that can occur outside the dialog.

141

142

```typescript { .api }

143

type FocusOutsideEvent = CustomEvent & {

144

target: Element;

145

preventDefault: () => void;

146

};

147

148

type InteractOutsideEvent = CustomEvent & {

149

target: Element;

150

preventDefault: () => void;

151

};

152

153

type PointerDownOutsideEvent = CustomEvent & {

154

target: Element;

155

preventDefault: () => void;

156

};

157

```

158

159

### Props Utilities

160

161

Utility functions for working with dialog props in framework integrations.

162

163

```typescript { .api }

164

/**

165

* Props utility for type-safe prop definitions

166

*/

167

const props: PropsDefinition<Props>;

168

169

/**

170

* Split props utility for separating dialog props from other props

171

* @param allProps - Object containing all props

172

* @returns Tuple with [dialogProps, otherProps]

173

*/

174

const splitProps: <T extends Partial<Props>>(

175

allProps: T & Record<string, any>

176

) => [T, Record<string, any>];

177

178

interface PropsDefinition<T> {

179

/** Array of prop keys for type validation */

180

keys: (keyof T)[];

181

/** Type-safe prop object */

182

object: T;

183

}

184

```

185

186

## Types

187

188

### Configuration Props

189

190

```typescript { .api }

191

interface Props {

192

// Element IDs

193

ids?: ElementIds;

194

195

// State Management

196

open?: boolean;

197

defaultOpen?: boolean;

198

onOpenChange?: (details: OpenChangeDetails) => void;

199

200

// Behavior Configuration

201

modal?: boolean;

202

trapFocus?: boolean;

203

preventScroll?: boolean;

204

restoreFocus?: boolean;

205

closeOnInteractOutside?: boolean;

206

closeOnEscape?: boolean;

207

208

// Accessibility

209

role?: "dialog" | "alertdialog";

210

"aria-label"?: string;

211

212

// Focus Management

213

initialFocusEl?: () => MaybeElement;

214

finalFocusEl?: () => MaybeElement;

215

216

// Event Handlers

217

onInteractOutside?: (event: InteractOutsideEvent) => void;

218

onFocusOutside?: (event: FocusOutsideEvent) => void;

219

onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;

220

onEscapeKeyDown?: (event: KeyboardEvent) => void;

221

onRequestDismiss?: () => void;

222

223

// Other

224

dir?: "ltr" | "rtl";

225

id?: string;

226

getRootNode?: () => Node | ShadowRoot | Document;

227

persistentElements?: () => Element[];

228

}

229

230

interface ElementIds {

231

trigger?: string;

232

positioner?: string;

233

backdrop?: string;

234

content?: string;

235

closeTrigger?: string;

236

title?: string;

237

description?: string;

238

}

239

240

interface OpenChangeDetails {

241

open: boolean;

242

}

243

244

type MaybeElement = Element | null | undefined;

245

```

246

247

### Service Types

248

249

```typescript { .api }

250

interface Service extends StateMachineService<DialogSchema> {

251

state: State;

252

send: (event: MachineEvent) => void;

253

context: Context;

254

prop: (key: string) => any;

255

scope: Scope;

256

}

257

258

interface DialogSchema {

259

props: Props;

260

state: "open" | "closed";

261

context: {

262

rendered: { title: boolean; description: boolean };

263

};

264

guard: "isOpenControlled";

265

effect: "trackDismissableElement" | "preventScroll" | "trapFocus" | "hideContentBelow";

266

action: "checkRenderedElements" | "syncZIndex" | "invokeOnClose" | "invokeOnOpen" | "toggleVisibility";

267

event: MachineEvent;

268

}

269

```