• tabs-panel (web component)

    From luserdroog@21:1/5 to All on Mon Jul 10 19:23:04 2023
    A <tabs-panel /> accepts contents for two slots, named "tab" and "content". The tabs are shown spaced out and clickable, controlling their associated content.

    Critique or comments welcome.

    tabs.html:
    <html>
    <body>
    <tabs-panel>
    <div slot="tab" data-target="#out1" class="active tab">first</div>
    <div slot="tab" data-target="#out2" class="tab">second</div>
    <div slot="tab" data-target="#out3" class="tab">third</div>
    <div id="out1" slot="content" class="active content">Content 1: the first</div>
    <div id="out2" slot="content" class="content">Content 2: which follows after</div>
    <div id="out3" slot="content" class="content">Content 3: where it all ends</div>
    </tabs-panel>
    </body>
    <script src="tabs.js"></script>
    </html>



    tabs.js:
    const tabsPanelTemplate = document.createElement( "template" ); tabsPanelTemplate.innerHTML = `
    <style>
    .tabs{
    display: flex;
    justify-content: flex-start;
    }
    ::slotted([slot="tab"]) {
    cursor: pointer;
    padding: 1ex;
    margin: 1ex;
    }
    ::slotted([slot="tab"].active) {
    border: solid 1px;
    }
    ::slotted([slot="content"]){
    display: none;
    }
    ::slotted([slot="content"].active){
    display: block;
    }
    </style>
    <slot name="tab" class="tabs"></slot>
    <hr>
    <slot name="content"></slot>
    `;

    class TabsPanel extends HTMLElement {
    constructor() {
    super();
    this.attachShadow( {mode:"open"} );
    this.shadowRoot.appendChild( tabsPanelTemplate.content.cloneNode(true) );
    }

    connectedCallback() {
    this.querySelectorAll('[slot="tab"]').forEach( tab => {
    tab.addEventListener( "click", e => {
    this.querySelectorAll("[slot]").forEach( tab => tab.classList.remove( "active" ) );
    tab.classList.add( "active" );
    this.querySelector( tab.dataset.target ).classList.add( "active" );
    })
    });
    }

    disconnectedCallback() {
    this.querySelectorAll('[slot="tab"]').forEach( tab => {
    tab.removeEventListener();
    });
    }
    };

    window.customElements.define( "tabs-panel", TabsPanel );

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael Haufe (TNO)@21:1/5 to luserdroog on Mon Jul 10 22:40:25 2023
    On Monday, July 10, 2023 at 9:23:09 PM UTC-5, luserdroog wrote:
    A <tabs-panel /> accepts contents for two slots, named "tab" and "content". The tabs are shown spaced out and clickable, controlling their associated content.

    Critique or comments welcome.
    [...]

    You can leverage <details /> for this too. Something like:

    <article class="tabs">
    <details class="tab">
    <summary class="tab-label">Tab 1</summary>
    <div class="tab-content">Content 1</div>
    </details>
    <details class="tab">
    <summary class="tab-label">Tab 2</summary>
    <div class="tab-content">Content 2</div>
    </details>
    <details class="tab">
    <summary class="tab-label">Tab 3</summary>
    <div class="tab-content">Content 3</div>
    </details>
    </article>

    <style>
    .tabs {
    position: relative;
    display: inline-flex;
    border: 1px solid blue;
    height: 300px;
    }

    .tab[open] {
    background-color: #ccc;
    }

    .tab-label {
    padding: 1em;
    border: 1px solid red;
    border-radius: 15% 15% 0 0;
    }

    .tab-content {
    position: absolute;
    background-color: cyan;
    left: 0;
    height: calc(100% - 3.1em);
    width: 100%;
    overflow: auto;
    }
    </style>

    You'll just want to toggle all sibling tabs when one is open by intercepting the 'toggle' event. Here's a quick codepen:

    <https://codepen.io/mlhaufe/pen/abQVrWg>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From luserdroog@21:1/5 to All on Tue Jul 11 06:35:24 2023
    On Tuesday, July 11, 2023 at 12:40:30 AM UTC-5, Michael Haufe (TNO) wrote:
    On Monday, July 10, 2023 at 9:23:09 PM UTC-5, luserdroog wrote:
    A <tabs-panel /> accepts contents for two slots, named "tab" and "content". The tabs are shown spaced out and clickable, controlling their associated content.

    Critique or comments welcome.
    [...]

    You can leverage <details /> for this too. Something like:


    That's pretty cool. <defensive reaction>I think there are real advantages
    of abstraction, encapsulation, and packaging with the web component
    approach. All the functionality is wrapped up in the component.
    The application doesn't have to do a thing beyond constructing the html. </defensive reaction>

    The clickable words should probably be <button>s for accessibility.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael Haufe (TNO)@21:1/5 to luserdroog on Tue Jul 11 09:53:02 2023
    On Tuesday, July 11, 2023 at 8:35:29 AM UTC-5, luserdroog wrote:
    On Tuesday, July 11, 2023 at 12:40:30 AM UTC-5, Michael Haufe (TNO) wrote:
    On Monday, July 10, 2023 at 9:23:09 PM UTC-5, luserdroog wrote:
    A <tabs-panel /> accepts contents for two slots, named "tab" and "content". The tabs are shown spaced out and clickable, controlling their associated content.

    Critique or comments welcome.
    [...]

    You can leverage <details /> for this too. Something like:

    That's pretty cool. <defensive reaction>I think there are real advantages
    of abstraction, encapsulation, and packaging with the web component approach. All the functionality is wrapped up in the component.
    The application doesn't have to do a thing beyond constructing the html. </defensive reaction>

    That was the hope on WebComponents, but I was burned bad by them and wrote a popular article criticizing them a handful of years ago:

    <https://thenewobjective.com/web-development/a-criticism-of-web-components>

    Things have improved, but not by much sadly

    The clickable words should probably be <button>s for accessibility.

    The <summary/> element already has an aria role of "button" so there is no need:

    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary#technical_summary>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)