Skip to content

Instantly share code, notes, and snippets.

@tobz-nz
Last active October 14, 2025 03:59
Show Gist options
  • Select an option

  • Save tobz-nz/2447216683e6733b4a6fc91b0e2b0ceb to your computer and use it in GitHub Desktop.

Select an option

Save tobz-nz/2447216683e6733b4a6fc91b0e2b0ceb to your computer and use it in GitHub Desktop.
A super simple pair of tab custom elements

Usage:

<script src="tabs.js" type="module"></script>
<style>
tab-window {
    display: none;

    &[open] {
        display: block;
    }
}
</style>

<tab-control group="some-group">
    <label><input type="radio" name="whatever" value="tab-1"> Tab 1</label>

    <label><input type="radio" name="whatever" value="tab-2"> Tab 2</label>
</tab-control>

<tab-window group="some-group" value="tab-1">
Tab 1 Content
</tab-window>

<tab-window group="some-group" value="tab-2">
Tab 2 Content
</tab-window>

<tab-window group="some-group" value="tab-1">
A second Tab 1 Window
</tab-window>

<tab-control group="some-group">
    A select control
    <select name="whatever">
        <option value="tab-1">Tab 1</option>
        <option value="tab-2">Tab 2</option>
    </select>
</tab-control>

<tab-control group="some-group" on="click">
    A button control
    <button type="button" value="tab-1">Tab 1</button>
    <button type="button" value="tab-2">Tab 2</button>
</tab-control>
customElements.define('tab-control', class extends HTMLElement {
#tabWindows = []
connectedCallback() {
this.addEventListener(this.on, this)
// Set the initial active tab window
Array.from(this.#tabWindows)
.find(tabWindow => tabWindow.value === this.activeTab)
?.toggle(true)
}
disconnectedCallback() {
this.removeEventListener(this.on, this)
}
handleEvent(event) {
if (event.type === this.on) {
// Toggle the open attribute on the tab window
this.#tabWindows.forEach(tabWindow => {
tabWindow.toggle(tabWindow.value === event.target.value)
})
}
}
get on() {
return this.getAttribute('on') || 'input'
}
set on(value) {
this.setAttribute('on', value)
}
get targets() {
return this.getAttribute('targets')
}
get activeTab() {
return this.getAttribute('active-tab')
}
add(tabWindow) {
this.#tabWindows.push(tabWindow)
}
})
customElements.define('tab-window', class extends HTMLElement {
connectedCallback() {
// push this window into the control's list of tab-windows
document.querySelectorAll(`tab-control[group="${this.group}"]`).forEach(control => control.add(this))
}
toggle(value) {
this.open = value
}
get group() {
return this.getAttribute('group')
}
set group(value) {
this.setAttribute('group', value)
}
get value() {
return this.getAttribute('value')
}
set value(value) {
this.setAttribute('value', value)
}
get open() {
return this.getAttribute('open')
}
set open(value) {
this.toggleAttribute('open', !!value)
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment