1 import {Component} from './component';
3 export interface TabsChangeEvent {
9 * Uses accessible attributes to drive its functionality.
10 * On tab wrapping element:
12 * On tabs (Should be a button):
15 * - aria-selected=true/false
16 * - aria-controls=<id-of-panel-section>
21 * - aria-labelledby=<id-of-tab-for-panel>
22 * - hidden (If not shown by default).
24 export class Tabs extends Component {
26 protected container!: HTMLElement;
27 protected tabList!: HTMLElement;
28 protected tabs!: HTMLElement[];
29 protected panels!: HTMLElement[];
31 protected activeUnder!: number;
32 protected active: null|boolean = null;
35 this.container = this.$el;
36 this.tabList = this.container.querySelector('[role="tablist"]') as HTMLElement;
37 this.tabs = Array.from(this.tabList.querySelectorAll('[role="tab"]'));
38 this.panels = Array.from(this.container.querySelectorAll(':scope > [role="tabpanel"], :scope > * > [role="tabpanel"]'));
39 this.activeUnder = this.$opts.activeUnder ? Number(this.$opts.activeUnder) : 10000;
41 this.container.addEventListener('click', event => {
42 const tab = (event.target as HTMLElement).closest('[role="tab"]');
43 if (tab instanceof HTMLElement && this.tabs.includes(tab)) {
44 this.show(tab.getAttribute('aria-controls') || '');
48 window.addEventListener('resize', this.updateActiveState.bind(this), {
51 this.updateActiveState();
54 public show(sectionId: string): void {
55 for (const panel of this.panels) {
56 panel.toggleAttribute('hidden', panel.id !== sectionId);
59 for (const tab of this.tabs) {
60 const tabSection = tab.getAttribute('aria-controls');
61 const selected = tabSection === sectionId;
62 tab.setAttribute('aria-selected', selected ? 'true' : 'false');
65 const data: TabsChangeEvent = {showing: sectionId};
66 this.$emit('change', data);
69 protected updateActiveState(): void {
70 const active = window.innerWidth < this.activeUnder;
71 if (active === this.active) {
84 protected activate(): void {
85 const panelToShow = this.panels.find(p => !p.hasAttribute('hidden')) || this.panels[0];
86 this.show(panelToShow.id);
87 this.tabList.toggleAttribute('hidden', false);
90 protected deactivate(): void {
91 for (const panel of this.panels) {
92 panel.removeAttribute('hidden');
94 for (const tab of this.tabs) {
95 tab.setAttribute('aria-selected', 'false');
97 this.tabList.toggleAttribute('hidden', true);