or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collaboration.mdcommands-and-editing.mdcursors-and-enhancements.mdhistory.mdindex.mdinput-and-keymaps.mdmarkdown.mdmenus-and-ui.mdmodel-and-schema.mdschema-definitions.mdstate-management.mdtables.mdtransformations.mdview-and-rendering.md

input-and-keymaps.mddocs/

0

# Input and Keymaps

1

2

Input rules provide automatic text transformations based on typing patterns, while keymaps bind keyboard commands to editor actions. Together they create responsive editing experiences.

3

4

## Capabilities

5

6

### Input Rules

7

8

Input rules automatically transform text as users type, providing shortcuts and typography improvements.

9

10

```typescript { .api }

11

/**

12

* An input rule transforms text based on pattern matching

13

*/

14

class InputRule {

15

/**

16

* Create a new input rule

17

*/

18

constructor(

19

match: RegExp,

20

handler: string | ((state: EditorState, match: string[], start: number, end: number) => Transaction | null),

21

options?: { undoable?: boolean }

22

);

23

}

24

```

25

26

### Input Rule Plugin

27

28

Create and manage input rule plugins.

29

30

```typescript { .api }

31

/**

32

* Create an input rules plugin

33

*/

34

function inputRules(config: { rules: InputRule[] }): Plugin;

35

36

/**

37

* Undo the last input rule transformation

38

*/

39

function undoInputRule(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;

40

```

41

42

### Input Rule Helpers

43

44

Convenient functions for common input rule patterns.

45

46

```typescript { .api }

47

/**

48

* Create an input rule that wraps matched text in a node

49

*/

50

function wrappingInputRule(

51

regexp: RegExp,

52

nodeType: NodeType,

53

getAttrs?: Attrs | ((match: string[]) => Attrs | null),

54

joinPredicate?: (match: string[], node: Node) => boolean

55

): InputRule;

56

57

/**

58

* Create an input rule that changes text block type

59

*/

60

function textblockTypeInputRule(

61

regexp: RegExp,

62

nodeType: NodeType,

63

getAttrs?: Attrs | ((match: string[]) => Attrs | null)

64

): InputRule;

65

```

66

67

### Typography Rules

68

69

Pre-defined input rules for common typography transformations.

70

71

```typescript { .api }

72

/**

73

* Convert -- to em dash

74

*/

75

const emDash: InputRule;

76

77

/**

78

* Convert ... to ellipsis character

79

*/

80

const ellipsis: InputRule;

81

82

/**

83

* Convert opening quotes

84

*/

85

const openDoubleQuote: InputRule;

86

87

/**

88

* Convert closing quotes

89

*/

90

const closeDoubleQuote: InputRule;

91

92

/**

93

* Convert opening single quotes

94

*/

95

const openSingleQuote: InputRule;

96

97

/**

98

* Convert closing single quotes

99

*/

100

const closeSingleQuote: InputRule;

101

102

/**

103

* Combined smart quote rules

104

*/

105

const smartQuotes: InputRule[];

106

```

107

108

### Keymap System

109

110

Keymaps bind keyboard shortcuts to editor commands.

111

112

```typescript { .api }

113

/**

114

* Create a keymap plugin from key bindings

115

*/

116

function keymap(bindings: { [key: string]: Command | false }): Plugin;

117

118

/**

119

* Create a keydown event handler from bindings

120

*/

121

function keydownHandler(bindings: { [key: string]: Command | false }): (view: EditorView, event: KeyboardEvent) => boolean;

122

```

123

124

### Key Notation

125

126

Key combinations use standard notation for cross-platform compatibility.

127

128

```typescript { .api }

129

/**

130

* Key binding specification

131

*/

132

interface KeyBinding {

133

[key: string]: Command | false;

134

}

135

136

/**

137

* Key notation examples:

138

* - "Mod-b" (Ctrl on PC/Linux, Cmd on Mac)

139

* - "Alt-Enter"

140

* - "Shift-Ctrl-z"

141

* - "Backspace"

142

* - "Delete"

143

* - "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"

144

* - "Home", "End"

145

* - "PageUp", "PageDown"

146

*/

147

```

148

149

**Usage Examples:**

150

151

```typescript

152

import {

153

InputRule,

154

inputRules,

155

wrappingInputRule,

156

textblockTypeInputRule,

157

smartQuotes,

158

emDash,

159

ellipsis

160

} from "@tiptap/pm/inputrules";

161

import { keymap } from "@tiptap/pm/keymap";

162

import { toggleMark, setBlockType } from "@tiptap/pm/commands";

163

164

// Custom input rules

165

const rules = [

166

// Convert ** to bold

167

new InputRule(

168

/\*\*([^*]+)\*\*$/,

169

(state, match, start, end) => {

170

const tr = state.tr.delete(start, end);

171

const mark = state.schema.marks.strong.create();

172

return tr.insert(start, state.schema.text(match[1], [mark]));

173

}

174

),

175

176

// Wrap selection in blockquote with >

177

wrappingInputRule(

178

/^\s*>\s$/,

179

state.schema.nodes.blockquote

180

),

181

182

// Convert # to heading

183

textblockTypeInputRule(

184

/^#\s/,

185

state.schema.nodes.heading,

186

{ level: 1 }

187

),

188

189

// Typography rules

190

...smartQuotes,

191

emDash,

192

ellipsis

193

];

194

195

// Create input rules plugin

196

const inputRulesPlugin = inputRules({ rules });

197

198

// Custom keymap

199

const myKeymap = keymap({

200

// Formatting

201

"Mod-b": toggleMark(schema.marks.strong),

202

"Mod-i": toggleMark(schema.marks.em),

203

"Mod-`": toggleMark(schema.marks.code),

204

205

// Block types

206

"Shift-Ctrl-1": setBlockType(schema.nodes.heading, { level: 1 }),

207

"Shift-Ctrl-2": setBlockType(schema.nodes.heading, { level: 2 }),

208

"Shift-Ctrl-0": setBlockType(schema.nodes.paragraph),

209

210

// Custom commands

211

"Mod-Enter": (state, dispatch) => {

212

if (dispatch) {

213

dispatch(state.tr.insertText("\n"));

214

}

215

return true;

216

},

217

218

// Disable default behavior

219

"Ctrl-d": false

220

});

221

222

// Combine with editor

223

const state = EditorState.create({

224

schema: mySchema,

225

plugins: [

226

inputRulesPlugin,

227

myKeymap

228

]

229

});

230

```

231

232

## Advanced Input Rules

233

234

### Conditional Rules

235

236

Create rules that apply conditionally based on context.

237

238

```typescript

239

// Only apply in specific node types

240

const codeBlockRule = new InputRule(

241

/```(\w+)?\s$/,

242

(state, match, start, end) => {

243

// Only apply at document level

244

if (state.selection.$from.depth > 1) return null;

245

246

const attrs = match[1] ? { language: match[1] } : {};

247

return state.tr

248

.delete(start, end)

249

.setBlockType(start, start, schema.nodes.code_block, attrs);

250

}

251

);

252

253

// Rules with custom undo behavior

254

const undoableRule = new InputRule(

255

/-->/g,

256

"→",

257

{ undoable: true }

258

);

259

```

260

261

### Complex Transformations

262

263

Input rules can perform sophisticated document transformations.

264

265

```typescript

266

// Auto-link URLs

267

const autoLinkRule = new InputRule(

268

/(https?:\/\/[^\s]+)$/,

269

(state, match, start, end) => {

270

const url = match[1];

271

const mark = schema.marks.link.create({ href: url });

272

return state.tr

273

.addMark(start, end, mark)

274

.insertText(" ", end);

275

}

276

);

277

278

// Smart list continuation

279

const listContinueRule = new InputRule(

280

/^(\d+)\.\s$/,

281

(state, match, start, end) => {

282

const number = parseInt(match[1]);

283

return state.tr

284

.delete(start, end)

285

.wrapIn(schema.nodes.ordered_list, { order: number })

286

.wrapIn(schema.nodes.list_item);

287

}

288

);

289

```

290

291

## Keymap Composition

292

293

### Layered Keymaps

294

295

Combine multiple keymaps with priority ordering.

296

297

```typescript

298

import { baseKeymap } from "@tiptap/pm/commands";

299

300

const editorKeymaps = [

301

// Highest priority - custom overrides

302

keymap({

303

"Enter": customEnterCommand,

304

"Tab": customTabCommand

305

}),

306

307

// Medium priority - feature-specific

308

keymap({

309

"Mod-k": insertLinkCommand,

310

"Mod-Shift-k": removeLinkCommand

311

}),

312

313

// Lowest priority - base commands

314

keymap(baseKeymap)

315

];

316

317

const state = EditorState.create({

318

schema: mySchema,

319

plugins: editorKeymaps

320

});

321

```

322

323

### Platform-Specific Bindings

324

325

Handle platform differences in key bindings.

326

327

```typescript

328

const platformKeymap = keymap({

329

// Cross-platform modifier

330

"Mod-z": undo,

331

"Mod-Shift-z": redo,

332

333

// Platform-specific alternatives

334

...(navigator.platform.includes("Mac") ? {

335

"Cmd-y": redo // Mac alternative

336

} : {

337

"Ctrl-y": redo // Windows/Linux alternative

338

})

339

});

340

```

341

342

## Types

343

344

```typescript { .api }

345

/**

346

* Input rule configuration

347

*/

348

interface InputRuleConfig {

349

rules: InputRule[];

350

}

351

352

/**

353

* Key binding map

354

*/

355

interface Keymap {

356

[key: string]: Command | false;

357

}

358

359

/**

360

* Input rule handler function

361

*/

362

type InputRuleHandler = (

363

state: EditorState,

364

match: string[],

365

start: number,

366

end: number

367

) => Transaction | null;

368

369

/**

370

* Input rule options

371

*/

372

interface InputRuleOptions {

373

undoable?: boolean;

374

}

375

```