0
# UI Components
1
2
Interactive UI components for user input and navigation, including tab bars, menu bars, command palettes, and scrollbars. These components provide the building blocks for creating rich user interfaces with professional desktop application features.
3
4
## Capabilities
5
6
### TabBar
7
8
A widget that displays titles as a single row or column of tabs with full interaction support.
9
10
```typescript { .api }
11
/**
12
* A widget that displays titles as a single row or column of tabs.
13
* Provides tab selection, reordering, closing, and other interactive features.
14
*/
15
class TabBar<T> extends Widget {
16
/**
17
* Construct a new tab bar.
18
* @param options - The options for initializing the tab bar
19
*/
20
constructor(options?: TabBar.IOptions<T>);
21
22
/** The renderer for the tab bar (read-only) */
23
readonly renderer: TabBar.IRenderer<T>;
24
25
/** The document context for the tab bar (read-only) */
26
readonly document: Document | ShadowRoot;
27
28
/** Whether the tabs are movable by the user */
29
tabsMovable: boolean;
30
31
/** Whether the title text can be edited by the user */
32
titlesEditable: boolean;
33
34
/** Whether a tab can be deselected by clicking it */
35
allowDeselect: boolean;
36
37
/** The insertion behavior when adding new tabs */
38
insertBehavior: TabBar.InsertBehavior;
39
40
/** The removal behavior when removing tabs */
41
removeBehavior: TabBar.RemoveBehavior;
42
43
/** The currently selected title, or null if no title is selected */
44
currentTitle: Title<T> | null;
45
46
/** The index of the currently selected tab, or -1 if no tab is selected */
47
currentIndex: number;
48
49
/** The name of the tab bar */
50
name: string;
51
52
/** The orientation of the tab bar */
53
orientation: TabBar.Orientation;
54
55
/** Whether the add button is enabled */
56
addButtonEnabled: boolean;
57
58
/** The titles managed by the tab bar (read-only) */
59
readonly titles: ReadonlyArray<Title<T>>;
60
61
/** The content node for the tab bar (read-only) */
62
readonly contentNode: HTMLUListElement;
63
64
/** The add button node for the tab bar (read-only) */
65
readonly addButtonNode: HTMLDivElement;
66
67
/** A signal emitted when the current tab changes */
68
readonly currentChanged: ISignal<this, TabBar.ICurrentChangedArgs<T>>;
69
70
/** A signal emitted when a tab is moved */
71
readonly tabMoved: ISignal<this, TabBar.ITabMovedArgs<T>>;
72
73
/** A signal emitted when a tab should be activated */
74
readonly tabActivateRequested: ISignal<this, TabBar.ITabActivateRequestedArgs<T>>;
75
76
/** A signal emitted when the add button is clicked */
77
readonly addRequested: ISignal<this, void>;
78
79
/** A signal emitted when a tab close is requested */
80
readonly tabCloseRequested: ISignal<this, TabBar.ITabCloseRequestedArgs<T>>;
81
82
/** A signal emitted when a tab detach is requested */
83
readonly tabDetachRequested: ISignal<this, TabBar.ITabDetachRequestedArgs<T>>;
84
85
/** Dispose of the tab bar and its resources */
86
dispose(): void;
87
88
/**
89
* Add a tab to the end of the tab bar.
90
* @param value - The title or options for creating the tab
91
* @returns The title object for the added tab
92
*/
93
addTab(value: Title<T> | Title.IOptions<T>): Title<T>;
94
95
/**
96
* Insert a tab at the specified index.
97
* @param index - The index at which to insert the tab
98
* @param value - The title or options for creating the tab
99
* @returns The title object for the inserted tab
100
*/
101
insertTab(index: number, value: Title<T> | Title.IOptions<T>): Title<T>;
102
103
/**
104
* Remove a tab from the tab bar.
105
* @param title - The title to remove
106
*/
107
removeTab(title: Title<T>): void;
108
109
/**
110
* Remove the tab at the specified index.
111
* @param index - The index of the tab to remove
112
*/
113
removeTabAt(index: number): void;
114
115
/** Remove all tabs from the tab bar */
116
clearTabs(): void;
117
118
/** Release the mouse grab for the tab bar */
119
releaseMouse(): void;
120
121
/** Handle DOM events for the tab bar */
122
handleEvent(event: Event): void;
123
}
124
125
namespace TabBar {
126
/**
127
* Options for initializing a tab bar.
128
*/
129
interface IOptions<T> {
130
/** The document context for the tab bar */
131
document?: Document | ShadowRoot;
132
133
/** Whether tabs are movable (default: false) */
134
tabsMovable?: boolean;
135
136
/** Whether titles are editable (default: false) */
137
titlesEditable?: boolean;
138
139
/** Whether tabs can be deselected (default: false) */
140
allowDeselect?: boolean;
141
142
/** The insertion behavior (default: 'select-tab-if-needed') */
143
insertBehavior?: InsertBehavior;
144
145
/** The removal behavior (default: 'select-tab-after') */
146
removeBehavior?: RemoveBehavior;
147
148
/** The name for the tab bar (default: '') */
149
name?: string;
150
151
/** The orientation (default: 'horizontal') */
152
orientation?: Orientation;
153
154
/** Whether add button is enabled (default: false) */
155
addButtonEnabled?: boolean;
156
157
/** The renderer for creating tab elements */
158
renderer?: IRenderer<T>;
159
}
160
161
/**
162
* The available orientations for a tab bar.
163
*/
164
type Orientation = 'horizontal' | 'vertical';
165
166
/**
167
* The available insertion behaviors for a tab bar.
168
*/
169
type InsertBehavior = 'select-tab' | 'select-tab-if-needed' | 'none';
170
171
/**
172
* The available removal behaviors for a tab bar.
173
*/
174
type RemoveBehavior = 'select-tab-after' | 'select-tab-before' | 'select-previous-tab' | 'none';
175
176
/**
177
* An object which renders the visual parts of a tab bar.
178
*/
179
interface IRenderer<T> {
180
/** The CSS selector for close icons in tab elements */
181
readonly closeIconSelector: string;
182
183
/**
184
* Render the virtual element for a tab.
185
* @param data - The render data for the tab
186
* @returns The virtual element for the tab
187
*/
188
renderTab(data: IRenderData<T>): VirtualElement;
189
}
190
191
/**
192
* The render data for a tab bar tab.
193
*/
194
interface IRenderData<T> {
195
/** The title for the tab */
196
title: Title<T>;
197
198
/** Whether the tab is current */
199
current: boolean;
200
201
/** The z-index for the tab */
202
zIndex: number;
203
}
204
205
/**
206
* Default tab bar renderer implementation.
207
*/
208
class Renderer implements IRenderer<any> {
209
/** The CSS selector for close icons */
210
readonly closeIconSelector: string;
211
212
/**
213
* Render the virtual element for a tab.
214
* @param data - The render data for the tab
215
* @returns The virtual element for the tab
216
*/
217
renderTab(data: IRenderData<any>): VirtualElement;
218
}
219
220
/** Signal argument interfaces */
221
interface ICurrentChangedArgs<T> {
222
previousIndex: number;
223
previousTitle: Title<T> | null;
224
currentIndex: number;
225
currentTitle: Title<T> | null;
226
}
227
228
interface ITabMovedArgs<T> {
229
fromIndex: number;
230
toIndex: number;
231
title: Title<T>;
232
}
233
234
interface ITabActivateRequestedArgs<T> {
235
index: number;
236
title: Title<T>;
237
}
238
239
interface ITabCloseRequestedArgs<T> {
240
index: number;
241
title: Title<T>;
242
}
243
244
interface ITabDetachRequestedArgs<T> {
245
index: number;
246
title: Title<T>;
247
clientX: number;
248
clientY: number;
249
offset: { x: number; y: number };
250
}
251
}
252
```
253
254
**Usage Examples:**
255
256
```typescript
257
import { Widget, TabBar, Title } from "@lumino/widgets";
258
259
// Create tab bar
260
const tabBar = new TabBar<Widget>({
261
orientation: 'horizontal',
262
tabsMovable: true,
263
insertBehavior: 'select-tab'
264
});
265
266
// Add tabs
267
const widget1 = new Widget();
268
const title1 = tabBar.addTab({
269
owner: widget1,
270
label: 'Document 1',
271
iconClass: 'fa fa-file',
272
closable: true
273
});
274
275
const widget2 = new Widget();
276
const title2 = tabBar.addTab({
277
owner: widget2,
278
label: 'Document 2',
279
closable: true
280
});
281
282
// Handle tab selection
283
tabBar.currentChanged.connect((sender, args) => {
284
console.log(`Selected tab: ${args.currentTitle?.label}`);
285
});
286
287
// Handle tab close requests
288
tabBar.tabCloseRequested.connect((sender, args) => {
289
tabBar.removeTab(args.title);
290
});
291
292
// Handle tab moves
293
tabBar.tabMoved.connect((sender, args) => {
294
console.log(`Moved tab from ${args.fromIndex} to ${args.toIndex}`);
295
});
296
```
297
298
### MenuBar
299
300
A widget that displays application menus in a horizontal bar.
301
302
```typescript { .api }
303
/**
304
* A widget that displays a menu bar for application menus.
305
* Manages a collection of menus with keyboard and mouse navigation.
306
*/
307
class MenuBar extends Widget {
308
/**
309
* Construct a new menu bar.
310
* @param options - The options for initializing the menu bar
311
*/
312
constructor(options?: MenuBar.IOptions);
313
314
/** The renderer for the menu bar (read-only) */
315
readonly renderer: MenuBar.IRenderer;
316
317
/** The currently active menu, or null if no menu is active */
318
readonly activeMenu: Menu | null;
319
320
/** The index of the active menu, or -1 if no menu is active */
321
activeIndex: number;
322
323
/** The menus in the menu bar (read-only) */
324
readonly menus: ReadonlyArray<Menu>;
325
326
/** The child menu for the menu bar (read-only) */
327
readonly childMenu: Menu | null;
328
329
/** The content node for the menu bar (read-only) */
330
readonly contentNode: HTMLUListElement;
331
332
/** The overflow index for the menu bar (read-only) */
333
readonly overflowIndex: number;
334
335
/** The overflow menu for the menu bar (read-only) */
336
readonly overflowMenu: Menu | null;
337
338
/** Dispose of the menu bar and its resources */
339
dispose(): void;
340
341
/**
342
* Add a menu to the end of the menu bar.
343
* @param menu - The menu to add
344
* @param update - Whether to update the menu bar immediately
345
*/
346
addMenu(menu: Menu, update?: boolean): void;
347
348
/**
349
* Insert a menu at the specified index.
350
* @param index - The index at which to insert the menu
351
* @param menu - The menu to insert
352
* @param update - Whether to update the menu bar immediately
353
*/
354
insertMenu(index: number, menu: Menu, update?: boolean): void;
355
356
/**
357
* Remove a menu from the menu bar.
358
* @param menu - The menu to remove
359
* @param update - Whether to update the menu bar immediately
360
*/
361
removeMenu(menu: Menu, update?: boolean): void;
362
363
/**
364
* Remove the menu at the specified index.
365
* @param index - The index of the menu to remove
366
* @param update - Whether to update the menu bar immediately
367
*/
368
removeMenuAt(index: number, update?: boolean): void;
369
370
/**
371
* Remove all menus from the menu bar.
372
* @param update - Whether to update the menu bar immediately
373
*/
374
clearMenus(update?: boolean): void;
375
376
/** Open the active menu */
377
openActiveMenu(): void;
378
379
/** Handle DOM events for the menu bar */
380
handleEvent(event: Event): void;
381
382
/** Activate the next menu in the menu bar */
383
activateNextMenu(): void;
384
385
/** Activate the previous menu in the menu bar */
386
activatePreviousMenu(): void;
387
}
388
389
namespace MenuBar {
390
/**
391
* Options for initializing a menu bar.
392
*/
393
interface IOptions extends Widget.IOptions {
394
/** The renderer for creating menu bar elements */
395
renderer?: IRenderer;
396
397
/** Options for forcing item positions */
398
forceItemsPosition?: Partial<IForceItemsPositionOptions>;
399
}
400
401
/**
402
* An object which renders the visual parts of a menu bar.
403
*/
404
interface IRenderer {
405
/**
406
* Create an item node for a menu bar item.
407
* @param data - The render data for the item
408
* @returns The item node for the menu
409
*/
410
createItemNode(data: IRenderData): HTMLLIElement;
411
412
/**
413
* Update an existing item node to reflect current state.
414
* @param node - The item node to update
415
* @param data - The render data for the item
416
*/
417
updateItemNode(node: HTMLLIElement, data: IRenderData): void;
418
419
/**
420
* Create an icon node for a menu bar item.
421
* @param data - The render data for the item
422
* @returns The icon node for the menu
423
*/
424
createIconNode(data: IRenderData): HTMLSpanElement;
425
426
/**
427
* Update an existing icon node to reflect current state.
428
* @param node - The icon node to update
429
* @param data - The render data for the item
430
*/
431
updateIconNode(node: HTMLSpanElement, data: IRenderData): void;
432
433
/**
434
* Create a label node for a menu bar item.
435
* @param data - The render data for the item
436
* @returns The label node for the menu
437
*/
438
createLabelNode(data: IRenderData): HTMLSpanElement;
439
440
/**
441
* Update an existing label node to reflect current state.
442
* @param node - The label node to update
443
* @param data - The render data for the item
444
*/
445
updateLabelNode(node: HTMLSpanElement, data: IRenderData): void;
446
}
447
448
/**
449
* The render data for a menu bar item.
450
*/
451
interface IRenderData {
452
/** The title for the menu */
453
title: Title<Menu>;
454
455
/** Whether the menu is active */
456
active: boolean;
457
}
458
459
/**
460
* Options for forcing menu item positions.
461
*/
462
interface IForceItemsPositionOptions {
463
/** Force items to the start position */
464
forceX: boolean;
465
466
/** Force items to the top position */
467
forceY: boolean;
468
}
469
470
/**
471
* Default menu bar renderer implementation.
472
*/
473
class Renderer implements IRenderer {
474
createItemNode(data: IRenderData): HTMLLIElement;
475
updateItemNode(node: HTMLLIElement, data: IRenderData): void;
476
createIconNode(data: IRenderData): HTMLSpanElement;
477
updateIconNode(node: HTMLSpanElement, data: IRenderData): void;
478
createLabelNode(data: IRenderData): HTMLSpanElement;
479
updateLabelNode(node: HTMLSpanElement, data: IRenderData): void;
480
}
481
}
482
```
483
484
**Usage Examples:**
485
486
```typescript
487
import { MenuBar, Menu } from "@lumino/widgets";
488
import { CommandRegistry } from "@lumino/commands";
489
490
// Create command registry
491
const commands = new CommandRegistry();
492
493
// Create menus
494
const fileMenu = new Menu({ commands });
495
fileMenu.title.label = 'File';
496
fileMenu.title.mnemonic = 0; // 'F' is underlined
497
498
const editMenu = new Menu({ commands });
499
editMenu.title.label = 'Edit';
500
editMenu.title.mnemonic = 0; // 'E' is underlined
501
502
// Create menu bar
503
const menuBar = new MenuBar();
504
menuBar.addMenu(fileMenu);
505
menuBar.addMenu(editMenu);
506
507
// Add menu items
508
fileMenu.addItem({ command: 'file:new' });
509
fileMenu.addItem({ command: 'file:open' });
510
fileMenu.addItem({ type: 'separator' });
511
fileMenu.addItem({ command: 'file:save' });
512
513
editMenu.addItem({ command: 'edit:cut' });
514
editMenu.addItem({ command: 'edit:copy' });
515
editMenu.addItem({ command: 'edit:paste' });
516
```
517
518
### CommandPalette
519
520
A widget that displays a searchable palette of commands for quick access.
521
522
```typescript { .api }
523
/**
524
* A widget that displays a palette of commands for quick access.
525
* Provides fuzzy search and keyboard navigation of available commands.
526
*/
527
class CommandPalette extends Widget {
528
/**
529
* Construct a new command palette.
530
* @param options - The options for initializing the command palette
531
*/
532
constructor(options: CommandPalette.IOptions);
533
534
/** The command registry for the palette (read-only) */
535
readonly commands: CommandRegistry;
536
537
/** The renderer for the palette (read-only) */
538
readonly renderer: CommandPalette.IRenderer;
539
540
/** The search input node for the palette (read-only) */
541
readonly searchNode: HTMLInputElement;
542
543
/** The input node for the palette (read-only) */
544
readonly inputNode: HTMLInputElement;
545
546
/** The content node for the palette (read-only) */
547
readonly contentNode: HTMLUListElement;
548
549
/**
550
* Add an item to the command palette.
551
* @param options - The options for creating the item
552
* @returns The command palette item that was added
553
*/
554
addItem(options: CommandPalette.IItemOptions): CommandPalette.IItem;
555
556
/**
557
* Add multiple items to the command palette.
558
* @param options - An array of options for creating items
559
* @returns An array of command palette items that were added
560
*/
561
addItems(options: CommandPalette.IItemOptions[]): CommandPalette.IItem[];
562
563
/**
564
* Remove an item from the command palette.
565
* @param item - The item to remove
566
*/
567
removeItem(item: CommandPalette.IItem): void;
568
569
/**
570
* Remove the item at the specified index.
571
* @param index - The index of the item to remove
572
*/
573
removeItemAt(index: number): void;
574
575
/** Remove all items from the command palette */
576
clearItems(): void;
577
578
/** Refresh the command palette display */
579
refresh(): void;
580
581
/** Handle DOM events for the command palette */
582
handleEvent(event: Event): void;
583
}
584
585
namespace CommandPalette {
586
/**
587
* Options for initializing a command palette.
588
*/
589
interface IOptions extends Widget.IOptions {
590
/** The command registry to use for the palette */
591
commands: CommandRegistry;
592
593
/** The renderer for creating palette elements */
594
renderer?: IRenderer;
595
}
596
597
/**
598
* An object which represents an item in a command palette.
599
*/
600
interface IItem {
601
/** The command identifier for the item */
602
command: string;
603
604
/** The arguments for the command */
605
args: any;
606
607
/** The category for the item */
608
category: string;
609
610
/** The rank for the item (lower ranks appear first) */
611
rank: number;
612
}
613
614
/**
615
* Options for creating a command palette item.
616
*/
617
interface IItemOptions {
618
/** The command identifier for the item */
619
command: string;
620
621
/** The arguments for the command (optional) */
622
args?: any;
623
624
/** The category for the item (default: '') */
625
category?: string;
626
627
/** The rank for the item (default: Infinity) */
628
rank?: number;
629
}
630
631
/**
632
* An object which renders the visual parts of a command palette.
633
*/
634
interface IRenderer {
635
/**
636
* Create an item node for a command palette item.
637
* @param data - The render data for the item
638
* @returns The item node for the command
639
*/
640
createItemNode(data: IRenderData): HTMLLIElement;
641
642
/**
643
* Update an existing item node to reflect current state.
644
* @param node - The item node to update
645
* @param data - The render data for the item
646
*/
647
updateItemNode(node: HTMLLIElement, data: IRenderData): void;
648
649
/**
650
* Create a category node for a command palette category.
651
* @param data - The render data for the category
652
* @returns The category node
653
*/
654
createCategoryNode(data: IRenderData): HTMLLIElement;
655
656
/**
657
* Update an existing category node to reflect current state.
658
* @param node - The category node to update
659
* @param data - The render data for the category
660
*/
661
updateCategoryNode(node: HTMLLIElement, data: IRenderData): void;
662
}
663
664
/**
665
* The render data for a command palette item.
666
*/
667
interface IRenderData {
668
/** The item being rendered */
669
item: IItem;
670
671
/** Whether the item is active */
672
active: boolean;
673
674
/** The indices of matched characters in the label */
675
indices: number[] | null;
676
}
677
678
/**
679
* Default command palette renderer implementation.
680
*/
681
class Renderer implements IRenderer {
682
createItemNode(data: IRenderData): HTMLLIElement;
683
updateItemNode(node: HTMLLIElement, data: IRenderData): void;
684
createCategoryNode(data: IRenderData): HTMLLIElement;
685
updateCategoryNode(node: HTMLLIElement, data: IRenderData): void;
686
}
687
}
688
```
689
690
**Usage Examples:**
691
692
```typescript
693
import { CommandPalette } from "@lumino/widgets";
694
import { CommandRegistry } from "@lumino/commands";
695
696
// Create command registry and add commands
697
const commands = new CommandRegistry();
698
699
commands.addCommand('file:new', {
700
label: 'New File',
701
iconClass: 'fa fa-file',
702
execute: () => console.log('Creating new file')
703
});
704
705
commands.addCommand('edit:find', {
706
label: 'Find in File',
707
iconClass: 'fa fa-search',
708
execute: () => console.log('Opening find dialog')
709
});
710
711
// Create command palette
712
const palette = new CommandPalette({ commands });
713
714
// Add items to palette
715
palette.addItem({
716
command: 'file:new',
717
category: 'File',
718
rank: 100
719
});
720
721
palette.addItem({
722
command: 'edit:find',
723
category: 'Edit',
724
rank: 200
725
});
726
727
// User can now search and execute commands
728
// Typing "new" will show the "New File" command
729
// Pressing Enter or clicking executes the command
730
```
731
732
### ScrollBar
733
734
A custom scrollbar widget for enhanced scrolling experiences.
735
736
```typescript { .api }
737
/**
738
* A custom scrollbar widget.
739
* Provides precise scroll control with customizable appearance and behavior.
740
*/
741
class ScrollBar extends Widget {
742
/**
743
* Construct a new scrollbar.
744
* @param options - The options for initializing the scrollbar
745
*/
746
constructor(options?: ScrollBar.IOptions);
747
748
/** The orientation of the scrollbar */
749
orientation: ScrollBar.Orientation;
750
751
/** The current value of the scrollbar */
752
value: number;
753
754
/** The page size for the scrollbar */
755
page: number;
756
757
/** The maximum value for the scrollbar */
758
maximum: number;
759
760
/** The decrement button node (read-only) */
761
readonly decrementNode: HTMLDivElement;
762
763
/** The increment button node (read-only) */
764
readonly incrementNode: HTMLDivElement;
765
766
/** The track node (read-only) */
767
readonly trackNode: HTMLDivElement;
768
769
/** The thumb node (read-only) */
770
readonly thumbNode: HTMLDivElement;
771
772
/** A signal emitted when the thumb position changes */
773
readonly thumbMoved: ISignal<this, number>;
774
775
/** A signal emitted when a step is requested */
776
readonly stepRequested: ISignal<this, 'decrement' | 'increment'>;
777
778
/** A signal emitted when a page step is requested */
779
readonly pageRequested: ISignal<this, 'decrement' | 'increment'>;
780
781
/** Handle DOM events for the scrollbar */
782
handleEvent(event: Event): void;
783
}
784
785
namespace ScrollBar {
786
/**
787
* Options for initializing a scrollbar.
788
*/
789
interface IOptions extends Widget.IOptions {
790
/** The orientation of the scrollbar (default: 'vertical') */
791
orientation?: Orientation;
792
793
/** The initial value (default: 0) */
794
value?: number;
795
796
/** The page size (default: 10) */
797
page?: number;
798
799
/** The maximum value (default: 100) */
800
maximum?: number;
801
}
802
803
/**
804
* The available orientations for a scrollbar.
805
*/
806
type Orientation = 'horizontal' | 'vertical';
807
}
808
```
809
810
**Usage Examples:**
811
812
```typescript
813
import { ScrollBar } from "@lumino/widgets";
814
815
// Create vertical scrollbar
816
const scrollBar = new ScrollBar({
817
orientation: 'vertical',
818
value: 0,
819
page: 10,
820
maximum: 100
821
});
822
823
// Handle scroll events
824
scrollBar.thumbMoved.connect((sender, value) => {
825
console.log(`Scrolled to position: ${value}`);
826
// Update content position based on scroll value
827
updateContentPosition(value);
828
});
829
830
scrollBar.stepRequested.connect((sender, direction) => {
831
const step = 1;
832
const newValue = direction === 'increment'
833
? Math.min(scrollBar.value + step, scrollBar.maximum)
834
: Math.max(scrollBar.value - step, 0);
835
scrollBar.value = newValue;
836
});
837
838
scrollBar.pageRequested.connect((sender, direction) => {
839
const newValue = direction === 'increment'
840
? Math.min(scrollBar.value + scrollBar.page, scrollBar.maximum)
841
: Math.max(scrollBar.value - scrollBar.page, 0);
842
scrollBar.value = newValue;
843
});
844
845
function updateContentPosition(value: number) {
846
// Update the position of scrollable content
847
const percentage = value / scrollBar.maximum;
848
// Apply scroll position to content
849
}
850
```