lion/demo/docs/20-lea-tabs.md
Jorge del Casar 98f1bb7e1c fix: normalize dependencies
Co-authored-by: jorenbroekema <Joren.Broekema@ing.com>
2021-01-06 10:53:38 +01:00

231 lines
6.8 KiB
Markdown

# lea Tabs
> This is not a real implementation!
>
> It is an example of how you can reuse the functionality of Lion to create your own Style System
`lea-tabs` implements tabs view to allow users to quickly move between a small number of equally important views.
```js script
import { html } from '@lion/core';
import { LitElement } from '@lion/core';
import '../lea-tabs.js';
import '../lea-tab.js';
import '../lea-tab-panel.js';
export default {
title: 'Intro/Tabs Example',
};
```
```js preview-story
export const main = () => html`
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```
## How to use
### Installation
```sh
npm i --save @lion/tabs;
```
### Usage
```js
import '@lion/tabs/lea-tabs.js';
```
```html
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
```
## Examples
### Selected Index
You can set the `selectedIndex` to select a certain tab.
```js preview-story
export const selectedIndex = () => html`
<lea-tabs .selectedIndex=${1}>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```
### Slots Order
The tab and panel slots are ordered by DOM order.
This means you can switch the grouping in your `lea-tabs` from tab + panel to all tabs first or all panels first.
```js preview-story
export const slotsOrder = () => html`
<lea-tabs>
<lea-tab slot="tab">Info</lea-tab>
<lea-tab slot="tab">Work</lea-tab>
<lea-tab-panel slot="panel"> Info page with lots of information about us. </lea-tab-panel>
<lea-tab-panel slot="panel"> Work page that showcases our work. </lea-tab-panel>
</lea-tabs>
`;
```
### Distribute New Elements
Below, we demonstrate on how you could dynamically add new tab + panels.
```js preview-story
export const distributeNewElements = () => {
const tagName = 'lea-tabs-experimental';
if (!customElements.get(tagName)) {
customElements.define(
tagName,
class extends LitElement {
static get properties() {
return {
__collection: { type: Array },
};
}
render() {
return html`
<h3>Append</h3>
<button @click="${this.__handleAppendClick}">Append</button>
<lea-tabs id="appendTabs">
<lea-tab slot="tab">tab 1</lea-tab>
<lea-tab-panel slot="panel">panel 1</lea-tab-panel>
<lea-tab slot="tab">tab 2</lea-tab>
<lea-tab-panel slot="panel">panel 2</lea-tab-panel>
</lea-tabs>
<hr />
<h3>Push</h3>
<button @click="${this.__handlePushClick}">Push</button>
<lea-tabs id="pushTabs">
<lea-tab slot="tab">tab 1</lea-tab>
<lea-tab-panel slot="panel">panel 1</lea-tab-panel>
<lea-tab slot="tab">tab 2</lea-tab>
<lea-tab-panel slot="panel">panel 2</lea-tab-panel>
${this.__collection.map(
item => html`
<lea-tab slot="tab">${item.button}</lea-tab>
<lea-tab-panel slot="panel">${item.panel}</lea-tab-panel>
`,
)}
</lea-tabs>
`;
}
constructor() {
super();
this.__collection = [];
}
__handleAppendClick() {
const tabsElement = this.shadowRoot.querySelector('#appendTabs');
const c = 2;
const n = Math.floor(tabsElement.children.length / 2);
for (let i = n + 1; i < n + c; i += 1) {
const tab = document.createElement('lea-tab');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${i}`;
const panel = document.createElement('lea-tab-panel');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${i}`;
tabsElement.append(tab);
tabsElement.append(panel);
}
}
__handlePushClick() {
const tabsElement = this.shadowRoot.querySelector('#pushTabs');
const i = Math.floor(tabsElement.children.length / 2) + 1;
this.__collection = [
...this.__collection,
{
button: `tab ${i}`,
panel: `panel ${i}`,
},
];
}
},
);
}
return html` <lea-tabs-experimental></lea-tabs-experimental> `;
};
```
One way is by creating the DOM elements and appending them as needed.
Inside your `lea-tabs` extension, an example for appending nodes on a certain button click:
```js
__handleAppendClick() {
const tabsAmount = this.children.length / 2;
const tab = document.createElement('lea-tab');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${tabsAmount + 1}`;
const panel = document.createElement('lea-tab-panel');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${tabsAmount + 1}`;
this.append(tab);
this.append(panel);
}
```
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.
```js
__handlePushClick() {
const tabsAmount = this.children.length;
myCollection = [
...myCollection,
{
button: `tab ${tabsAmount + 1}`,
panel: `panel ${tabsAmount + 1}`,
},
];
renderMyCollection();
}
```
Make sure your template re-renders when myCollection is updated.
```html
<lea-tabs id="pushTabs">
${myCollection.map(item => html`
<lea-tab slot="tab">${item.button}</lea-tab>
<lea-tab-panel slot="panel">${item.panel}</lea-tab-panel>
`)}
</lea-tabs>
```
## Rationale
### No separate active/focus state when using keyboard
We will immediately switch content as all our content comes from light dom (e.g. no latency)
See Note at <https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-19>
> It is recommended that tabs activate automatically when they receive focus as long as their
> associated tab panels are displayed without noticeable latency. This typically requires tab
> panel content to be preloaded.
### Panels are not focusable
Focusable elements should have a means to interact with them. Tab panels themselves do not offer any interactiveness.
If there is a button or a form inside the tab panel then these elements get focused directly.