lion/docs/components/content/accordion/features.md

6.1 KiB

Content >> Accordion >> Features ||20

import { LitElement, html } from '@lion/core';

import '@lion/accordion/define';

Expanded

You can set expanded to pre-expand a certain invoker.

export const expanded = () => html`
  <lion-accordion .expanded=${[1]}>
    <h3 slot="invoker">
      <button>Lorem</button>
    </h3>
    <p slot="content">Lorem ipsum dolor sit, amet consectetur adipisicing elit.</p>
    <h3 slot="invoker">
      <button>Laboriosam</button>
    </h3>
    <p slot="content">
      Laboriosam sequi odit cumque, enim aut assumenda itaque quis voluptas est quos fugiat unde
      labore reiciendis saepe, iure, optio officiis obcaecati quibusdam.
    </p>
  </lion-accordion>
`;

Slots Order

The invoker and content slots are ordered by DOM order.

export const slotsOrder = () => html`
  <lion-accordion>
    <h3 slot="invoker">
      <button>Lorem</button>
    </h3>
    <p slot="content">Lorem ipsum dolor sit, amet consectetur adipisicing elit.</p>
    <h3 slot="invoker">
      <button>Laboriosam</button>
    </h3>
    <p slot="content">
      Laboriosam sequi odit cumque, enim aut assumenda itaque quis voluptas est quos fugiat unde
      labore reiciendis saepe, iure, optio officiis obcaecati quibusdam.
    </p>
  </lion-accordion>
`;

Multiline header

A header can be multiline.

export const multilineHeader = () => html`
  <lion-accordion>
    <h3 slot="invoker">
      <button>
        header 1 with
        <br />
        multiple lines
      </button>
    </h3>
    <p slot="content">content 1</p>
    <h3 slot="invoker">
      <button>header 2</button>
    </h3>
    <p slot="content">content 2</p>
  </lion-accordion>
`;

Distribute New Elements

Below, we demonstrate how you could dynamically add a new invoker + content.

export const distributeNewElement = () => {
  const tagName = 'demo-accordion-add-dynamically';
  if (!customElements.get(tagName)) {
    customElements.define(
      tagName,
      class extends LitElement {
        static get properties() {
          return {
            __collection: { type: Array },
          };
        }
        render() {
          return html`
            <h3>Append</h3>
            <lion-accordion id="appendAccordion">
              <h4 slot="invoker">
                <button>header 1</button>
              </h4>
              <p slot="content">content 1</p>
              <h4 slot="invoker">
                <button>header 2</button>
              </h4>
              <p slot="content">content 2</p>
            </lion-accordion>
            <button @click="${this.__handleAppendClick}">Append</button>
            <hr />
            <h3>Push</h3>
            <lion-accordion id="pushTabs">
              <h4 slot="invoker">
                <button>header 1</button>
              </h4>
              <p slot="content">content 1</p>
              <h4 slot="invoker">
                <button>header 2</button>
              </h4>
              <p slot="content">content 2</p>
              ${this.__collection.map(
                item => html`
                  <h4 slot="invoker"><button>${item.invoker}</button></h4>
                  <p slot="content">${item.content}</p>
                `,
              )}
            </lion-accordion>
            <button @click="${this.__handlePushClick}">Push</button>
          `;
        }
        constructor() {
          super();
          this.__collection = [];
        }
        __handleAppendClick() {
          const accordionElement = this.shadowRoot.querySelector('#appendAccordion');
          const c = 2;
          const n = Math.floor(accordionElement.children.length / 2);
          for (let i = n + 1; i < n + c; i += 1) {
            const invoker = document.createElement('h4');
            const button = document.createElement('button');
            button.innerText = `header ${i}`;
            invoker.setAttribute('slot', 'invoker');
            invoker.appendChild(button);
            const content = document.createElement('p');
            content.setAttribute('slot', 'content');
            content.innerText = `content ${i}`;
            accordionElement.append(invoker);
            accordionElement.append(content);
          }
        }
        __handlePushClick() {
          const accordionElement = this.shadowRoot.querySelector('#pushTabs');
          const i = Math.floor(accordionElement.children.length / 2) + 1;
          this.__collection = [
            ...this.__collection,
            {
              invoker: `header ${i}`,
              content: `content ${i}`,
            },
          ];
        }
      },
    );
  }
  return html` <demo-accordion-add-dynamically></demo-accordion-add-dynamically> `;
};

One way is by creating the DOM elements and appending them as needed.

Inside your lion-accordion extension, an example for appending nodes on a certain button click:

__handleAppendClick() {
  const accordionAmount = this.children.length / 2;
  const invoker = document.createElement('h4');
  const button = document.createElement('button');
  button.innerText = `header ${accordionAmount + 1}`;
  invoker.setAttribute('slot', 'invoker');
  invoker.appendChild(button);
  const content = document.createElement('p');
  content.setAttribute('slot', 'content');
  content.innerText = `content ${accordionAmount + 1}`;
  this.append(invoker);
  this.append(content);
}

The other way is by adding data to a Lit property where you loop over this property in your template. You then need to ensure this causes a re-render.

__handlePushClick() {
  const accordionAmount = this.children.length;
  myCollection = [
    ...myCollection,
    {
      invoker: `header ${accordionAmount + 1}`,
      content: `content ${accordionAmount + 1}`,
    },
  ];
  renderMyCollection();
}

Make sure your template re-renders when myCollection is updated.

<lion-accordion id="pushAccordion">
  ${myCollection.map(item => html`
  <h4 slot="invoker">
    <button>${item.invoker}</button>
  </h4>
  <p slot="content">${item.content}</p>
  `)}
</lion-accordion>