or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-framework.mdcommands.mddependency-injection.mdevents-messaging.mdindex.mdkeybindings.mdmenus.mdpreferences-configuration.mdresources-files.mdwidgets-ui.md

widgets-ui.mddocs/

0

# Widgets and UI

1

2

Theia's widget system provides comprehensive UI components built on Phosphor/Lumino with React integration, layout management, and extensible widget types for building modern IDE interfaces.

3

4

## Capabilities

5

6

### Base Widget

7

8

Foundation widget class providing core widget functionality and lifecycle management.

9

10

```typescript { .api }

11

/**

12

* Base widget class for all UI components

13

*/

14

class Widget {

15

/** Unique widget identifier */

16

readonly id: string;

17

18

/** Widget title with label, icon, and other metadata */

19

readonly title: Title<Widget>;

20

21

/** Parent widget if this widget is attached */

22

readonly parent: Widget | null;

23

24

/** True if widget is attached to DOM */

25

readonly isAttached: boolean;

26

27

/** True if widget is visible */

28

readonly isVisible: boolean;

29

30

/** True if widget is disposed */

31

readonly isDisposed: boolean;

32

33

/**

34

* Show the widget

35

*/

36

show(): void;

37

38

/**

39

* Hide the widget

40

*/

41

hide(): void;

42

43

/**

44

* Close the widget

45

*/

46

close(): void;

47

48

/**

49

* Dispose the widget and clean up resources

50

*/

51

dispose(): void;

52

53

/**

54

* Activate the widget (give it focus)

55

*/

56

activate(): void;

57

58

/**

59

* Update the widget's appearance

60

*/

61

update(): void;

62

}

63

```

64

65

### React Widget

66

67

Widget base class for React-based components with lifecycle integration.

68

69

```typescript { .api }

70

/**

71

* Widget that renders React components

72

*/

73

class ReactWidget extends Widget {

74

/**

75

* Create React widget with optional props

76

* @param props - React component props

77

*/

78

constructor(props?: any);

79

80

/**

81

* Render the React component

82

* @returns React element to render

83

*/

84

protected render(): React.ReactNode;

85

86

/**

87

* Called after widget is attached to DOM

88

*/

89

protected onAfterAttach(): void;

90

91

/**

92

* Called before widget is detached from DOM

93

*/

94

protected onBeforeDetach(): void;

95

96

/**

97

* Called when widget is updated

98

*/

99

protected onUpdateRequest(): void;

100

101

/**

102

* Set React component state

103

* @param state - New state object

104

* @param callback - Optional callback after state update

105

*/

106

protected setState(state: any, callback?: () => void): void;

107

}

108

```

109

110

**Usage Example:**

111

112

```typescript

113

import React from "react";

114

import { ReactWidget } from "@theia/core/lib/browser";

115

116

interface MyWidgetState {

117

count: number;

118

}

119

120

export class MyCounterWidget extends ReactWidget {

121

protected state: MyWidgetState = { count: 0 };

122

123

constructor() {

124

super();

125

this.id = 'counter-widget';

126

this.title.label = 'Counter';

127

this.title.iconClass = 'fa fa-calculator';

128

}

129

130

protected render(): React.ReactNode {

131

return (

132

<div className="counter-widget">

133

<h3>Count: {this.state.count}</h3>

134

<button onClick={this.increment}>Increment</button>

135

<button onClick={this.decrement}>Decrement</button>

136

</div>

137

);

138

}

139

140

private increment = (): void => {

141

this.setState({ count: this.state.count + 1 });

142

};

143

144

private decrement = (): void => {

145

this.setState({ count: this.state.count - 1 });

146

};

147

}

148

```

149

150

### Application Shell

151

152

Main application container that manages widget layout and areas.

153

154

```typescript { .api }

155

/**

156

* Main application shell managing widget layout

157

*/

158

class ApplicationShell extends Widget {

159

/**

160

* Add widget to specified area

161

* @param widget - Widget to add

162

* @param area - Shell area to add to

163

* @param options - Optional layout options

164

*/

165

addWidget(widget: Widget, area?: ApplicationShell.Area, options?: ApplicationShell.WidgetOptions): void;

166

167

/**

168

* Activate a widget

169

* @param id - Widget ID to activate

170

*/

171

activateWidget(id: string): Widget | undefined;

172

173

/**

174

* Close all widgets in area

175

* @param area - Shell area to close

176

*/

177

closeAll(area?: ApplicationShell.Area): void;

178

179

/**

180

* Get all widgets in area

181

* @param area - Shell area

182

* @returns Array of widgets in area

183

*/

184

getWidgets(area: ApplicationShell.Area): Widget[];

185

}

186

187

namespace ApplicationShell {

188

/**

189

* Shell areas where widgets can be placed

190

*/

191

enum Area {

192

left = 'left',

193

right = 'right',

194

main = 'main',

195

bottom = 'bottom',

196

top = 'top'

197

}

198

199

/**

200

* Options for adding widgets to shell

201

*/

202

interface WidgetOptions {

203

/** Area to add widget to */

204

area?: Area;

205

/** Tab index for ordering */

206

rank?: number;

207

/** Reference widget for relative positioning */

208

ref?: Widget;

209

/** Insertion mode relative to reference */

210

mode?: 'tab-after' | 'tab-before' | 'split-top' | 'split-bottom' | 'split-left' | 'split-right';

211

}

212

}

213

214

/**

215

* Service token for ApplicationShell

216

*/

217

const ApplicationShell: symbol;

218

```

219

220

### Widget Manager

221

222

Manages widget lifecycle, creation, and disposal.

223

224

```typescript { .api }

225

/**

226

* Manages widget lifecycle and factories

227

*/

228

interface WidgetManager {

229

/**

230

* Get or create widget by ID

231

* @param id - Widget ID

232

* @returns Promise resolving to widget

233

*/

234

getOrCreateWidget<T extends Widget>(id: string): Promise<T>;

235

236

/**

237

* Try to get existing widget

238

* @param id - Widget ID

239

* @returns Widget if exists, undefined otherwise

240

*/

241

tryGetWidget<T extends Widget>(id: string): T | undefined;

242

243

/**

244

* Get all widgets of a specific type

245

* @param factoryId - Widget factory ID

246

* @returns Array of matching widgets

247

*/

248

getWidgets<T extends Widget>(factoryId: string): T[];

249

}

250

251

/**

252

* Factory for creating widgets

253

*/

254

interface WidgetFactory {

255

/** Unique factory identifier */

256

readonly id: string;

257

258

/**

259

* Create widget instance

260

* @param options - Creation options

261

* @returns Promise resolving to widget

262

*/

263

createWidget(options?: any): Promise<Widget>;

264

}

265

266

/**

267

* Service tokens

268

*/

269

const WidgetManager: symbol;

270

const WidgetFactory: symbol;

271

```

272

273

### Saveable Widget

274

275

Widget mixin for widgets that contain saveable content.

276

277

```typescript { .api }

278

/**

279

* Widget that contains saveable content

280

*/

281

interface SaveableWidget extends Widget {

282

/**

283

* Save the widget's content

284

* @returns Promise that resolves when save completes

285

*/

286

save(): Promise<void>;

287

288

/**

289

* True if widget has unsaved changes

290

*/

291

readonly dirty: boolean;

292

293

/**

294

* Event fired when dirty state changes

295

*/

296

readonly onDirtyChanged: Event<void>;

297

}

298

299

namespace SaveableWidget {

300

/**

301

* Type guard for saveable widgets

302

* @param widget - Widget to check

303

* @returns True if widget is saveable

304

*/

305

function is(widget: Widget): widget is SaveableWidget;

306

}

307

```

308

309

**Usage Example:**

310

311

```typescript

312

import { ReactWidget, SaveableWidget } from "@theia/core/lib/browser";

313

import { Emitter, Event } from "@theia/core";

314

315

export class MyEditorWidget extends ReactWidget implements SaveableWidget {

316

private readonly onDirtyChangedEmitter = new Emitter<void>();

317

readonly onDirtyChanged: Event<void> = this.onDirtyChangedEmitter.event;

318

319

private _dirty = false;

320

private content = '';

321

322

get dirty(): boolean {

323

return this._dirty;

324

}

325

326

private setDirty(dirty: boolean): void {

327

if (this._dirty !== dirty) {

328

this._dirty = dirty;

329

this.onDirtyChangedEmitter.fire();

330

this.title.className = dirty ? 'dirty' : '';

331

}

332

}

333

334

async save(): Promise<void> {

335

await this.saveContent(this.content);

336

this.setDirty(false);

337

}

338

339

private updateContent(newContent: string): void {

340

this.content = newContent;

341

this.setDirty(true);

342

this.update();

343

}

344

345

private async saveContent(content: string): Promise<void> {

346

// Save implementation

347

}

348

}

349

```

350

351

### Widget Extensions

352

353

Additional widget utilities and extensions for specialized use cases.

354

355

```typescript { .api }

356

/**

357

* Widget that can be extracted to separate window

358

*/

359

interface ExtractableWidget extends Widget {

360

/**

361

* True if widget can be extracted

362

*/

363

readonly isExtractable: boolean;

364

365

/**

366

* Extract widget to separate window

367

*/

368

extractWidget(): void;

369

}

370

371

/**

372

* Stateful widget that can save/restore state

373

*/

374

interface StatefulWidget extends Widget {

375

/**

376

* Store widget state

377

* @returns State object

378

*/

379

storeState(): any;

380

381

/**

382

* Restore widget state

383

* @param oldState - Previously stored state

384

*/

385

restoreState(oldState: any): void;

386

}

387

388

/**

389

* Widget with custom context menu

390

*/

391

interface ContextMenuWidget extends Widget {

392

/**

393

* Create context menu for widget

394

* @param event - Mouse event

395

* @returns Context menu items

396

*/

397

createContextMenu(event: MouseEvent): ContextMenu;

398

}

399

```

400

401

### Title and Tabs

402

403

Widget title management and tab behavior.

404

405

```typescript { .api }

406

/**

407

* Widget title containing label, icon, and metadata

408

*/

409

class Title<T> {

410

/** Display label */

411

label: string;

412

413

/** Icon CSS class */

414

iconClass: string;

415

416

/** Icon label for accessibility */

417

iconLabel: string;

418

419

/** Caption/tooltip text */

420

caption: string;

421

422

/** CSS class name */

423

className: string;

424

425

/** True if title can be closed */

426

closable: boolean;

427

428

/** Dataset for custom attributes */

429

dataset: Record<string, string>;

430

431

/** Owner widget */

432

readonly owner: T;

433

434

/** Event fired when title changes */

435

readonly changed: Event<void>;

436

}

437

```

438

439

## Layout and Styling

440

441

### CSS Classes

442

443

Common CSS classes used by Theia widgets:

444

445

```typescript { .api }

446

/**

447

* Standard CSS classes for widgets

448

*/

449

namespace WidgetCSS {

450

const WIDGET = 'theia-widget';

451

const PANEL = 'theia-panel';

452

const TOOLBAR = 'theia-toolbar';

453

const TAB_BAR = 'theia-tab-bar';

454

const DOCK_PANEL = 'theia-dock-panel';

455

const SPLIT_PANEL = 'theia-split-panel';

456

}

457

```

458

459

### Layout Options

460

461

```typescript { .api }

462

/**

463

* Layout configuration for widgets

464

*/

465

interface LayoutOptions {

466

/** Minimum width in pixels */

467

minWidth?: number;

468

469

/** Minimum height in pixels */

470

minHeight?: number;

471

472

/** Maximum width in pixels */

473

maxWidth?: number;

474

475

/** Maximum height in pixels */

476

maxHeight?: number;

477

478

/** Stretch factor for resizing */

479

stretch?: number;

480

}

481

```

482

483

## Types

484

485

```typescript { .api }

486

/**

487

* Widget-related type definitions

488

*/

489

type WidgetConstructor = new (...args: any[]) => Widget;

490

491

interface WidgetOptions {

492

id?: string;

493

title?: Partial<Title.Dataset>;

494

}

495

496

namespace Widget {

497

/**

498

* Widget message types

499

*/

500

enum MessageType {

501

BeforeAttach = 'before-attach',

502

AfterAttach = 'after-attach',

503

BeforeDetach = 'before-detach',

504

AfterDetach = 'after-detach',

505

BeforeShow = 'before-show',

506

AfterShow = 'after-show',

507

BeforeHide = 'before-hide',

508

AfterHide = 'after-hide',

509

CloseRequest = 'close-request',

510

Resize = 'resize',

511

UpdateRequest = 'update-request',

512

FitRequest = 'fit-request',

513

ActivateRequest = 'activate-request'

514

}

515

}

516

```