or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-context.mdcontent-accessibility.mddialog-root.mdindex.mdportal-layout.mdtriggers-controls.md

triggers-controls.mddocs/

0

# Triggers and Controls

1

2

Components for opening and closing dialogs with proper accessibility, keyboard navigation, and focus management.

3

4

## Capabilities

5

6

### DialogTrigger

7

8

Button component that opens the dialog when activated, with automatic accessibility attributes.

9

10

```typescript { .api }

11

/**

12

* Button component that opens the dialog when activated

13

* Extends all standard button props and automatically adds accessibility attributes

14

*/

15

type DialogTriggerElement = React.ComponentRef<typeof Primitive.button>;

16

interface DialogTriggerProps extends React.ComponentPropsWithoutRef<typeof Primitive.button> {}

17

18

const DialogTrigger: React.ForwardRefExoticComponent<

19

DialogTriggerProps & React.RefAttributes<DialogTriggerElement>

20

>;

21

```

22

23

**Usage Examples:**

24

25

```typescript

26

import { Dialog, DialogTrigger, DialogContent } from "@radix-ui/react-dialog";

27

28

// Basic trigger

29

function BasicTrigger() {

30

return (

31

<Dialog>

32

<DialogTrigger>Open Dialog</DialogTrigger>

33

<DialogContent>Content here</DialogContent>

34

</Dialog>

35

);

36

}

37

38

// Custom styled trigger

39

function StyledTrigger() {

40

return (

41

<Dialog>

42

<DialogTrigger className="custom-button" disabled={false}>

43

<span className="icon">๐Ÿ“‹</span>

44

Open Settings

45

</DialogTrigger>

46

<DialogContent>Settings content</DialogContent>

47

</Dialog>

48

);

49

}

50

51

// Trigger with custom click handler

52

function TriggerWithHandler() {

53

const handleClick = (event: React.MouseEvent) => {

54

console.log('Trigger clicked');

55

// Dialog will still open automatically

56

};

57

58

return (

59

<Dialog>

60

<DialogTrigger onClick={handleClick}>

61

Open with Custom Handler

62

</DialogTrigger>

63

<DialogContent>Content here</DialogContent>

64

</Dialog>

65

);

66

}

67

68

// Using asChild pattern with existing element

69

function AsChildTrigger() {

70

return (

71

<Dialog>

72

<DialogTrigger asChild>

73

<button className="existing-button-class">

74

Open Dialog

75

</button>

76

</DialogTrigger>

77

<DialogContent>Content here</DialogContent>

78

</Dialog>

79

);

80

}

81

```

82

83

### DialogClose

84

85

Button component that closes the dialog when activated, can be placed anywhere within the dialog content.

86

87

```typescript { .api }

88

/**

89

* Button component that closes the dialog when activated

90

* Can be placed anywhere within dialog content

91

* Extends all standard button props

92

*/

93

type DialogCloseElement = React.ComponentRef<typeof Primitive.button>;

94

interface DialogCloseProps extends React.ComponentPropsWithoutRef<typeof Primitive.button> {}

95

96

const DialogClose: React.ForwardRefExoticComponent<

97

DialogCloseProps & React.RefAttributes<DialogCloseElement>

98

>;

99

```

100

101

**Usage Examples:**

102

103

```typescript

104

import { Dialog, DialogTrigger, DialogContent, DialogClose } from "@radix-ui/react-dialog";

105

106

// Basic close button

107

function BasicClose() {

108

return (

109

<Dialog>

110

<DialogTrigger>Open</DialogTrigger>

111

<DialogContent>

112

<p>Dialog content</p>

113

<DialogClose>Close</DialogClose>

114

</DialogContent>

115

</Dialog>

116

);

117

}

118

119

// Multiple close buttons

120

function MultipleCloseButtons() {

121

return (

122

<Dialog>

123

<DialogTrigger>Open</DialogTrigger>

124

<DialogContent>

125

<div className="dialog-header">

126

<h2>Confirm Action</h2>

127

<DialogClose className="close-icon">ร—</DialogClose>

128

</div>

129

<p>Are you sure you want to continue?</p>

130

<div className="dialog-actions">

131

<DialogClose className="cancel-btn">Cancel</DialogClose>

132

<DialogClose className="confirm-btn">Confirm</DialogClose>

133

</div>

134

</DialogContent>

135

</Dialog>

136

);

137

}

138

139

// Close button with custom handler

140

function CloseWithHandler() {

141

const handleClose = (event: React.MouseEvent) => {

142

console.log('Dialog closing');

143

// Dialog will still close automatically

144

};

145

146

return (

147

<Dialog>

148

<DialogTrigger>Open</DialogTrigger>

149

<DialogContent>

150

<p>Content here</p>

151

<DialogClose onClick={handleClose}>

152

Close with Handler

153

</DialogClose>

154

</DialogContent>

155

</Dialog>

156

);

157

}

158

159

// Using asChild pattern

160

function AsChildClose() {

161

return (

162

<Dialog>

163

<DialogTrigger>Open</DialogTrigger>

164

<DialogContent>

165

<p>Content here</p>

166

<DialogClose asChild>

167

<button className="existing-close-class">

168

Close Dialog

169

</button>

170

</DialogClose>

171

</DialogContent>

172

</Dialog>

173

);

174

}

175

```

176

177

## Accessibility Features

178

179

### DialogTrigger Accessibility

180

181

The DialogTrigger component automatically provides:

182

183

- `type="button"` for proper button semantics

184

- `aria-haspopup="dialog"` to indicate it opens a dialog

185

- `aria-expanded` that reflects the current dialog state

186

- `aria-controls` that references the dialog content ID

187

- `data-state` attribute with "open" or "closed" values

188

189

### DialogClose Accessibility

190

191

The DialogClose component automatically provides:

192

193

- `type="button"` for proper button semantics

194

- Proper event handling for keyboard activation (Enter, Space)

195

- Focus restoration to the trigger when dialog closes

196

197

## Event Handling

198

199

Both components compose event handlers, meaning you can add your own click handlers and they will be called alongside the built-in dialog control logic:

200

201

```typescript

202

// Your handler is called first, then the built-in logic

203

<DialogTrigger onClick={(e) => {

204

console.log('Custom logic before opening');

205

// Dialog opens automatically after this

206

}}>

207

Open

208

</DialogTrigger>

209

210

<DialogClose onClick={(e) => {

211

console.log('Custom logic before closing');

212

// Dialog closes automatically after this

213

}}>

214

Close

215

</DialogClose>

216

```

217

218

## Styling and Customization

219

220

Both components render as buttons by default but can be customized:

221

222

### CSS Classes and Styling

223

224

```typescript

225

<DialogTrigger className="btn btn-primary" style={{ fontSize: '16px' }}>

226

Styled Trigger

227

</DialogTrigger>

228

229

<DialogClose className="btn btn-secondary" data-testid="close-btn">

230

Styled Close

231

</DialogClose>

232

```

233

234

### AsChild Pattern

235

236

Use the `asChild` prop to render the functionality on your own element:

237

238

```typescript

239

<DialogTrigger asChild>

240

<YourCustomButton>Open</YourCustomButton>

241

</DialogTrigger>

242

243

<DialogClose asChild>

244

<YourCustomCloseIcon />

245

</DialogClose>

246

```