or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-system.mdcore-rendering.mdevent-handling.mdfragments-utilities.mdindex.mdrefs.mdvnode-creation.md
tile.json

event-handling.mddocs/

0

# Event Handling

1

2

Optimized event handling system with linkEvent for performance optimization and comprehensive synthetic event support for cross-browser compatibility.

3

4

## Capabilities

5

6

### Link Event

7

8

Performance-optimized event handling that links data to event handlers to avoid closure creation.

9

10

```typescript { .api }

11

/**

12

* Links data to event handlers for performance optimization

13

* @param data - Data to be passed as first argument to event handler

14

* @param event - Event handler function that receives data and event

15

* @returns LinkedEvent object or null if event is invalid

16

*/

17

function linkEvent<T, E extends Event>(

18

data: T,

19

event: (data: T, event: E) => void

20

): LinkedEvent<T, E> | null;

21

22

interface LinkedEvent<T, E extends Event> {

23

data: T;

24

event: (data: T, event: E) => void;

25

}

26

```

27

28

**Usage Examples:**

29

30

```typescript

31

import { linkEvent, createVNode, VNodeFlags } from "inferno";

32

33

class TodoList extends Component {

34

constructor(props) {

35

super(props);

36

this.state = { todos: [] };

37

}

38

39

// Event handler that receives data and event

40

handleRemoveTodo = (todoId, event) => {

41

this.setState(prevState => ({

42

todos: prevState.todos.filter(todo => todo.id !== todoId)

43

}));

44

};

45

46

render() {

47

return createVNode(VNodeFlags.HtmlElement, 'ul', null,

48

this.state.todos.map(todo =>

49

createVNode(VNodeFlags.HtmlElement, 'li', null, [

50

todo.text,

51

createVNode(VNodeFlags.HtmlElement, 'button', null, 'Remove', ChildFlags.HasInvalidChildren, {

52

// linkEvent passes todo.id as first argument to handler

53

onClick: linkEvent(todo.id, this.handleRemoveTodo)

54

})

55

])

56

)

57

);

58

}

59

}

60

61

// Alternative without linkEvent (less efficient)

62

class TodoListSlow extends Component {

63

handleRemoveTodo = (todoId) => (event) => {

64

// Creates new closure for each todo item

65

this.setState(prevState => ({

66

todos: prevState.todos.filter(todo => todo.id !== todoId)

67

}));

68

};

69

70

render() {

71

return createVNode(VNodeFlags.HtmlElement, 'ul', null,

72

this.state.todos.map(todo =>

73

createVNode(VNodeFlags.HtmlElement, 'li', null, [

74

todo.text,

75

createVNode(VNodeFlags.HtmlElement, 'button', null, 'Remove', ChildFlags.HasInvalidChildren, {

76

onClick: this.handleRemoveTodo(todo.id) // Creates closure

77

})

78

])

79

)

80

);

81

}

82

}

83

```

84

85

### Is Link Event Object

86

87

Utility function to check if an object is a linked event.

88

89

```typescript { .api }

90

/**

91

* Checks if an object is a linked event object

92

* @param o - Object to check

93

* @returns True if object is a LinkedEvent

94

*/

95

function isLinkEventObject(o: any): o is LinkedEvent<any, any>;

96

```

97

98

## Event Types

99

100

Comprehensive event handler types for all standard DOM events:

101

102

### Generic Event Handlers

103

104

```typescript { .api }

105

type EventHandler<E extends SemiSyntheticEvent<any>> =

106

| { bivarianceHack(event: E): void }['bivarianceHack']

107

| LinkedEvent<any, E>

108

| null;

109

110

type InfernoEventHandler<T = Element> = EventHandler<SemiSyntheticEvent<T>>;

111

```

112

113

### Specific Event Handlers

114

115

```typescript { .api }

116

type ClipboardEventHandler<T = Element> = EventHandler<ClipboardEvent<T>>;

117

type CompositionEventHandler<T = Element> = EventHandler<CompositionEvent<T>>;

118

type DragEventHandler<T = Element> = EventHandler<DragEvent<T>>;

119

type FocusEventHandler<T = Element> = EventHandler<FocusEvent<T>>;

120

type FormEventHandler<T = Element> = EventHandler<FormEvent<T>>;

121

type ChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;

122

type KeyboardEventHandler<T = Element> = EventHandler<InfernoKeyboardEvent<T>>;

123

type MouseEventHandler<T = Element> = EventHandler<InfernoMouseEvent<T>>;

124

type TouchEventHandler<T = Element> = EventHandler<InfernoTouchEvent<T>>;

125

type PointerEventHandler<T = Element> = EventHandler<InfernoPointerEvent<T>>;

126

type UIEventHandler<T = Element> = EventHandler<InfernoUIEvent<T>>;

127

type WheelEventHandler<T = Element> = EventHandler<InfernoWheelEvent<T>>;

128

type AnimationEventHandler<T = Element> = EventHandler<InfernoAnimationEvent<T>>;

129

type TransitionEventHandler<T = Element> = EventHandler<InfernoTransitionEvent<T>>;

130

```

131

132

## Synthetic Events

133

134

Inferno provides synthetic events for cross-browser compatibility:

135

136

### Base Synthetic Event

137

138

```typescript { .api }

139

interface SemiSyntheticEvent<T> extends Event {

140

/** A reference to the element on which the event listener is registered */

141

currentTarget: EventTarget & T;

142

isDefaultPrevented?: () => boolean;

143

isPropagationStopped?: () => boolean;

144

}

145

```

146

147

### Specific Event Types

148

149

```typescript { .api }

150

type ClipboardEvent<T> = SemiSyntheticEvent<T> & NativeClipboardEvent;

151

type CompositionEvent<T> = SemiSyntheticEvent<T> & NativeCompositionEvent;

152

type DragEvent<T> = InfernoMouseEvent<T> & NativeDragEvent;

153

type FocusEvent<T> = SemiSyntheticEvent<T> & NativeFocusEvent;

154

155

interface FormEvent<T> extends SemiSyntheticEvent<T> {

156

target: EventTarget & T;

157

}

158

159

interface ChangeEvent<T> extends SemiSyntheticEvent<T> {

160

target: EventTarget & T;

161

}

162

163

type InfernoKeyboardEvent<T> = SemiSyntheticEvent<T> & KeyboardEvent;

164

type InfernoMouseEvent<T> = SemiSyntheticEvent<T> & MouseEvent & {

165

target: EventTarget & T;

166

};

167

type InfernoTouchEvent<T> = SemiSyntheticEvent<T> & TouchEvent;

168

type InfernoPointerEvent<T> = SemiSyntheticEvent<T> & PointerEvent;

169

type InfernoUIEvent<T> = SemiSyntheticEvent<T> & UIEvent;

170

type InfernoWheelEvent<T> = InfernoMouseEvent<T> & WheelEvent;

171

type InfernoAnimationEvent<T> = SemiSyntheticEvent<T> & AnimationEvent;

172

type InfernoTransitionEvent<T> = SemiSyntheticEvent<T> & TransitionEvent;

173

```

174

175

## Event Usage Examples

176

177

### Mouse Events

178

179

```typescript

180

class ClickableComponent extends Component {

181

handleClick = (event: InfernoMouseEvent<HTMLButtonElement>) => {

182

console.log('Button clicked', event.currentTarget);

183

event.preventDefault();

184

};

185

186

handleMouseEnter = (message, event) => {

187

console.log(message, event.type);

188

};

189

190

render() {

191

return createVNode(VNodeFlags.HtmlElement, 'button', null, 'Click me', ChildFlags.HasInvalidChildren, {

192

onClick: this.handleClick,

193

onMouseEnter: linkEvent('Mouse entered!', this.handleMouseEnter)

194

});

195

}

196

}

197

```

198

199

### Form Events

200

201

```typescript

202

class FormComponent extends Component {

203

constructor(props) {

204

super(props);

205

this.state = { value: '' };

206

}

207

208

handleChange = (event: ChangeEvent<HTMLInputElement>) => {

209

this.setState({ value: event.target.value });

210

};

211

212

handleSubmit = (event: FormEvent<HTMLFormElement>) => {

213

event.preventDefault();

214

console.log('Submitted:', this.state.value);

215

};

216

217

render() {

218

return createVNode(VNodeFlags.HtmlElement, 'form', null, [

219

createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {

220

type: 'text',

221

value: this.state.value,

222

onChange: this.handleChange

223

}),

224

createVNode(VNodeFlags.HtmlElement, 'button', null, 'Submit', ChildFlags.HasInvalidChildren, {

225

type: 'submit'

226

})

227

], ChildFlags.HasNonKeyedChildren, {

228

onSubmit: this.handleSubmit

229

});

230

}

231

}

232

```

233

234

### Keyboard Events

235

236

```typescript

237

class KeyboardComponent extends Component {

238

handleKeyDown = (event: InfernoKeyboardEvent<HTMLInputElement>) => {

239

if (event.key === 'Enter') {

240

console.log('Enter pressed');

241

} else if (event.key === 'Escape') {

242

console.log('Escape pressed');

243

}

244

};

245

246

render() {

247

return createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {

248

onKeyDown: this.handleKeyDown,

249

placeholder: 'Press Enter or Escape'

250

});

251

}

252

}

253

```

254

255

## Performance Benefits of linkEvent

256

257

1. **No Closure Creation**: Avoids creating new functions for each render

258

2. **Memory Efficiency**: Reduces memory usage in lists with many items

259

3. **Consistent Performance**: Event handler creation cost is constant regardless of list size

260

4. **Garbage Collection**: Fewer objects created means less GC pressure

261

262

## Event Delegation

263

264

Inferno uses event delegation for improved performance:

265

266

- Events are attached to the document root instead of individual elements

267

- Single event listener handles all events of the same type

268

- Reduces memory usage and improves performance for large DOMs

269

- Automatically handles dynamically added/removed elements

270

271

## Cross-Browser Compatibility

272

273

Synthetic events provide consistent behavior across browsers:

274

275

- Normalized event properties and methods

276

- Consistent event bubbling and capturing

277

- Standardized preventDefault() and stopPropagation()

278

- Touch event support for mobile devices

279

- Pointer event support for modern browsers