or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

delta-operations.mdeditor-core.mdformatting-system.mdindex.mdmodule-system.mdregistry-system.mdtheme-system.md

theme-system.mddocs/

0

# Theme System

1

2

Theme system providing Snow and Bubble themes with customizable UI components and toolbar layouts. Themes control the visual presentation and user interface elements of the Quill editor, including toolbar positioning, styling, and interactive behaviors.

3

4

## Capabilities

5

6

### Base Theme Class

7

8

Abstract base class that all Quill themes extend, providing common UI management functionality.

9

10

```typescript { .api }

11

/**

12

* Base theme class for UI management

13

*/

14

abstract class Theme {

15

/** Default theme configuration options */

16

static DEFAULTS: Record<string, unknown>;

17

18

/** Theme registry for available themes */

19

static themes: Record<string, ThemeConstructor>;

20

21

/** Quill instance this theme belongs to */

22

quill: Quill;

23

24

/** Theme configuration options */

25

options: Record<string, unknown>;

26

27

/** Registered modules for this theme */

28

modules: Record<string, Module>;

29

30

/**

31

* Create theme instance

32

* @param quill - Quill editor instance

33

* @param options - Theme configuration options

34

*/

35

constructor(quill: Quill, options: Record<string, unknown>);

36

37

/**

38

* Initialize theme after construction

39

*/

40

init(): void;

41

42

/**

43

* Add and initialize module

44

* @param name - Module name

45

* @returns Initialized module instance

46

*/

47

addModule(name: string): Module;

48

}

49

50

interface ThemeOptions {

51

[key: string]: unknown;

52

}

53

54

interface ThemeConstructor {

55

new (quill: Quill, options: ThemeOptions): Theme;

56

DEFAULTS: ThemeOptions;

57

}

58

```

59

60

**Usage Examples:**

61

62

```typescript

63

// Define custom theme

64

class CustomTheme extends Theme {

65

static DEFAULTS = {

66

modules: {

67

toolbar: [

68

['bold', 'italic'],

69

['link']

70

]

71

}

72

};

73

74

constructor(quill, options) {

75

super(quill, options);

76

this.buildCustomUI();

77

}

78

79

init() {

80

super.init();

81

this.setupCustomBehaviors();

82

}

83

84

buildCustomUI() {

85

// Custom UI setup

86

}

87

}

88

89

// Register custom theme

90

Quill.register('themes/custom', CustomTheme);

91

92

// Use custom theme

93

const quill = new Quill('#editor', {

94

theme: 'custom'

95

});

96

```

97

98

### Snow Theme

99

100

Professional theme with toolbar positioned above the editor, suitable for document editing interfaces.

101

102

```typescript { .api }

103

class SnowTheme extends BaseTheme {

104

static DEFAULTS: {

105

modules: {

106

toolbar: ToolbarConfig;

107

};

108

};

109

110

/**

111

* Extend toolbar with Snow-specific features

112

* @param toolbar - Toolbar module instance

113

*/

114

extendToolbar(toolbar: Toolbar): void;

115

116

/**

117

* Build Snow theme UI

118

*/

119

buildTheme(): void;

120

}

121

122

class SnowTooltip extends BaseTooltip {

123

/** Root element for tooltip */

124

root: HTMLElement;

125

126

/**

127

* Listen for tooltip events

128

*/

129

listen(): void;

130

131

/**

132

* Show tooltip at position

133

*/

134

show(): void;

135

136

/**

137

* Hide tooltip

138

*/

139

hide(): void;

140

141

/**

142

* Position tooltip relative to reference

143

* @param reference - Reference element or bounds

144

*/

145

position(reference: HTMLElement | Bounds): void;

146

}

147

```

148

149

**Usage Examples:**

150

151

```typescript

152

// Use Snow theme (default)

153

const quill = new Quill('#editor', {

154

theme: 'snow',

155

modules: {

156

toolbar: [

157

[{ 'header': [1, 2, 3, false] }],

158

['bold', 'italic', 'underline'],

159

[{ 'color': [] }, { 'background': [] }],

160

[{ 'list': 'ordered'}, { 'list': 'bullet' }],

161

[{ 'align': [] }],

162

['link', 'image', 'video'],

163

['clean']

164

]

165

}

166

});

167

168

// Snow theme with custom toolbar container

169

const quill2 = new Quill('#editor2', {

170

theme: 'snow',

171

modules: {

172

toolbar: {

173

container: '#toolbar-container'

174

}

175

}

176

});

177

178

// Access Snow-specific features

179

const toolbar = quill.getModule('toolbar');

180

// Snow theme adds link editing functionality

181

```

182

183

### Bubble Theme

184

185

Contextual theme with floating toolbar that appears near selected text, suitable for inline editing scenarios.

186

187

```typescript { .api }

188

class BubbleTheme extends BaseTheme {

189

static DEFAULTS: {

190

modules: {

191

toolbar: ToolbarConfig;

192

};

193

};

194

195

/**

196

* Extend toolbar with Bubble-specific features

197

* @param toolbar - Toolbar module instance

198

*/

199

extendToolbar(toolbar: Toolbar): void;

200

201

/**

202

* Build Bubble theme UI

203

*/

204

buildTheme(): void;

205

}

206

207

class BubbleTooltip extends BaseTooltip {

208

/**

209

* Show tooltip at current selection

210

*/

211

show(): void;

212

213

/**

214

* Hide tooltip

215

*/

216

hide(): void;

217

218

/**

219

* Position tooltip near selection

220

*/

221

position(): void;

222

}

223

```

224

225

**Usage Examples:**

226

227

```typescript

228

// Use Bubble theme

229

const quill = new Quill('#editor', {

230

theme: 'bubble',

231

modules: {

232

toolbar: [

233

['bold', 'italic'],

234

['link'],

235

[{ 'header': 1 }, { 'header': 2 }]

236

]

237

}

238

});

239

240

// Bubble theme shows toolbar on text selection

241

// No permanent toolbar is visible

242

243

// Custom bubble configuration

244

const quill2 = new Quill('#editor2', {

245

theme: 'bubble',

246

bounds: '#editor-container', // Constrain bubble to container

247

modules: {

248

toolbar: [

249

['bold', 'italic', 'underline'],

250

['link']

251

]

252

}

253

});

254

```

255

256

### Base Theme Components

257

258

Common UI components used across themes.

259

260

```typescript { .api }

261

/**

262

* Base theme with common UI functionality

263

*/

264

class BaseTheme extends Theme {

265

/** Array of picker instances */

266

pickers: Picker[];

267

268

/** Tooltip instance */

269

tooltip: BaseTooltip;

270

271

/**

272

* Build toolbar buttons

273

* @param buttons - Button elements

274

* @param icons - Icon definitions

275

*/

276

buildButtons(buttons: HTMLElement[], icons: Record<string, string>): void;

277

278

/**

279

* Build picker controls

280

* @param selects - Select elements

281

* @param icons - Icon definitions

282

*/

283

buildPickers(selects: HTMLElement[], icons: Record<string, string>): void;

284

}

285

286

/**

287

* Base tooltip functionality

288

*/

289

class BaseTooltip extends Tooltip {

290

/** Text input element */

291

textbox: HTMLInputElement;

292

293

/** Current link range being edited */

294

linkRange: Range | null;

295

296

/**

297

* Enter edit mode

298

* @param mode - Edit mode ('link', 'video', 'formula')

299

* @param preview - Preview element

300

*/

301

edit(mode?: string, preview?: HTMLElement): void;

302

303

/**

304

* Cancel editing

305

*/

306

cancel(): void;

307

308

/**

309

* Save changes

310

*/

311

save(): void;

312

313

/**

314

* Set up event listeners

315

*/

316

listen(): void;

317

318

/**

319

* Restore focus to editor

320

*/

321

restoreFocus(): void;

322

}

323

```

324

325

**Usage Examples:**

326

327

```typescript

328

// Access theme components

329

const quill = new Quill('#editor', { theme: 'snow' });

330

331

// Get tooltip for custom functionality

332

const theme = quill.theme;

333

if (theme.tooltip) {

334

// Custom tooltip behavior

335

theme.tooltip.edit('link');

336

}

337

338

// Access pickers

339

if (theme.pickers) {

340

theme.pickers.forEach(picker => {

341

// Custom picker behavior

342

picker.update();

343

});

344

}

345

```

346

347

### UI Components

348

349

Reusable UI components used by themes.

350

351

```typescript { .api }

352

/**

353

* Dropdown picker component

354

*/

355

class Picker {

356

/** Original select element */

357

select: HTMLSelectElement;

358

359

/** Picker container element */

360

container: HTMLElement;

361

362

/** Picker label element */

363

label: HTMLElement;

364

365

/** Picker options container */

366

options: HTMLElement;

367

368

/**

369

* Build picker UI from select element

370

*/

371

buildPicker(): void;

372

373

/**

374

* Close picker dropdown

375

*/

376

close(): void;

377

378

/**

379

* Escape picker (close without selection)

380

*/

381

escape(): void;

382

383

/**

384

* Select item

385

* @param item - Item to select

386

* @param trigger - Whether to trigger change event

387

*/

388

selectItem(item: HTMLElement, trigger?: boolean): void;

389

390

/**

391

* Toggle picker visibility

392

*/

393

togglePicker(): void;

394

395

/**

396

* Update picker state

397

*/

398

update(): void;

399

}

400

401

/**

402

* Color picker component

403

*/

404

class ColorPicker extends Picker {

405

/**

406

* Build color picker with color swatches

407

*/

408

buildItem(option: HTMLOptionElement): HTMLElement;

409

}

410

411

/**

412

* Icon picker component

413

*/

414

class IconPicker extends Picker {

415

/**

416

* Build icon picker with SVG icons

417

*/

418

buildItem(option: HTMLOptionElement): HTMLElement;

419

}

420

421

/**

422

* Tooltip component

423

*/

424

class Tooltip {

425

/** Root tooltip element */

426

root: HTMLElement;

427

428

/** Quill instance */

429

quill: Quill;

430

431

/** Bounds for positioning */

432

boundsContainer: HTMLElement;

433

434

/**

435

* Hide tooltip

436

*/

437

hide(): void;

438

439

/**

440

* Position tooltip relative to reference

441

* @param reference - Reference element or bounds

442

*/

443

position(reference: HTMLElement | Bounds): void;

444

445

/**

446

* Show tooltip

447

*/

448

show(): void;

449

}

450

```

451

452

**Usage Examples:**

453

454

```typescript

455

// Access UI components

456

const quill = new Quill('#editor', {

457

theme: 'snow',

458

modules: {

459

toolbar: [

460

[{ 'color': [] }],

461

[{ 'background': [] }]

462

]

463

}

464

});

465

466

const toolbar = quill.getModule('toolbar');

467

const theme = quill.theme;

468

469

// Find color pickers

470

const colorPickers = theme.pickers.filter(picker => {

471

return picker.select.classList.contains('ql-color');

472

});

473

474

// Custom picker behavior

475

colorPickers.forEach(picker => {

476

picker.container.addEventListener('click', (e) => {

477

console.log('Color picker clicked');

478

});

479

});

480

```

481

482

### Theme Customization

483

484

Customize existing themes or create new ones.

485

486

```typescript { .api }

487

// Extend Snow theme

488

class CustomSnowTheme extends SnowTheme {

489

constructor(quill, options) {

490

super(quill, options);

491

this.addCustomStyles();

492

}

493

494

addCustomStyles() {

495

// Add custom CSS classes

496

this.quill.container.classList.add('custom-snow');

497

}

498

499

extendToolbar(toolbar) {

500

super.extendToolbar(toolbar);

501

502

// Add custom toolbar functionality

503

toolbar.addHandler('custom', (value) => {

504

// Custom handler

505

});

506

}

507

}

508

509

// Register custom theme

510

Quill.register('themes/custom-snow', CustomSnowTheme);

511

```

512

513

**Usage Examples:**

514

515

```typescript

516

// Theme with custom CSS

517

const quill = new Quill('#editor', {

518

theme: 'snow'

519

});

520

521

// Add custom CSS classes

522

quill.container.classList.add('dark-theme');

523

524

// Custom theme configuration

525

const quill2 = new Quill('#editor2', {

526

theme: 'snow',

527

modules: {

528

toolbar: {

529

container: [

530

[{ 'header': [1, 2, 3, false] }],

531

['bold', 'italic'],

532

['custom-button'] // Custom button

533

],

534

handlers: {

535

'custom-button': () => {

536

console.log('Custom button clicked');

537

}

538

}

539

}

540

}

541

});

542

543

// No theme (base editor only)

544

const quill3 = new Quill('#editor3'); // No theme specified

545

546

// Theme switching

547

function switchTheme(themeName) {

548

// Destroy current editor

549

const content = quill.getContents();

550

quill.container.innerHTML = '';

551

552

// Create new editor with different theme

553

const newQuill = new Quill(quill.container, {

554

theme: themeName,

555

modules: quill.options.modules

556

});

557

558

// Restore content

559

newQuill.setContents(content);

560

561

return newQuill;

562

}

563

564

// Switch to bubble theme

565

const bubbleQuill = switchTheme('bubble');

566

```

567

568

### Theme Events and Integration

569

570

Themes can listen to editor events and provide custom behaviors.

571

572

```typescript { .api }

573

class EventfulTheme extends Theme {

574

constructor(quill, options) {

575

super(quill, options);

576

this.setupEventListeners();

577

}

578

579

setupEventListeners() {

580

this.quill.on('selection-change', this.onSelectionChange.bind(this));

581

this.quill.on('text-change', this.onTextChange.bind(this));

582

}

583

584

onSelectionChange(range, oldRange, source) {

585

// Theme-specific selection handling

586

if (range) {

587

this.showContextualUI(range);

588

} else {

589

this.hideContextualUI();

590

}

591

}

592

593

onTextChange(delta, oldDelta, source) {

594

// Theme-specific text change handling

595

this.updateUI();

596

}

597

}

598

```

599

600

**Usage Examples:**

601

602

```typescript

603

// Theme with custom event handling

604

class InteractiveTheme extends SnowTheme {

605

constructor(quill, options) {

606

super(quill, options);

607

608

// Add selection highlighting

609

this.quill.on('selection-change', (range) => {

610

if (range && range.length > 0) {

611

this.highlightSelection(range);

612

} else {

613

this.clearHighlight();

614

}

615

});

616

}

617

618

highlightSelection(range) {

619

// Add visual selection indicator

620

const bounds = this.quill.getBounds(range);

621

if (bounds) {

622

this.showSelectionIndicator(bounds);

623

}

624

}

625

626

clearHighlight() {

627

this.hideSelectionIndicator();

628

}

629

}

630

631

Quill.register('themes/interactive', InteractiveTheme);

632

633

const quill = new Quill('#editor', {

634

theme: 'interactive'

635

});

636

```