UNPKG

preline

Version:

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

326 lines (237 loc) 11.7 kB
# Tabs Tabs make it easy to switch between different views. [![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/tabs) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Demo](https://img.shields.io/badge/demo-online-brightgreen)](https://preline.co/plugins/tabs.html) ## Contents - [Overview](#overview) - [Installation](#installation) - [Basic usage](#basic-usage) - [Accessibility notes](#accessibility-notes) - [Configuration Options](#configuration-options) - [JavaScript API](#javascript-api) - [Events](#events) - [Common Patterns](#common-patterns) - [License](#license) ## Overview The Tabs component allows users to switch between different content sections within the same context. It supports keyboard navigation, programmatic control, and customizable event types for activation. **Key Features:** - Multiple tab panels in a single group - Keyboard navigation support (Arrow keys, Home, End, Enter) - Customizable activation events (click, hover) - Programmatic control via JavaScript API - Event system for tab change tracking - Accessibility attributes (ARIA) built-in ## Installation To get started, install Tabs plugin via npm, else you can skip this step if you are already using Preline UI as a package. ```bash npm i @preline/tabs ``` ### CSS Use [`@source`](https://tailwindcss.com/docs/functions-and-directives#source-directive) to register the plugin's JavaScript path for Tailwind CSS scanning, then [`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS files into your Tailwind CSS file. ```css @import "tailwindcss"; /* @preline/tabs */ @source "../node_modules/@preline/tabs/*.js"; @import "./node_modules/@preline/tabs/variants.css"; @import "./node_modules/@preline/tabs/theme.css"; ``` ### JavaScript Include the JavaScript that powers the interactive elements near the end of your `</body>` tag: ```html <script src="./node_modules/@preline/tabs/index.js"></script> ``` ### Manual Initialization Use the `non-auto` entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly. ```html <script type="module"> import HSTabs from "@preline/tabs/non-auto.mjs"; new HSTabs(document.querySelector("#tabs")); </script> ``` ### Via Bundler When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module. `@preline/tabs` is the auto-init entry: it scans the DOM and initializes matching elements automatically. ```js import "@preline/tabs"; ``` `@preline/tabs/non-auto` is the manual entry: use it when you want explicit control over when initialization happens, either via `autoInit()` or by creating a specific instance yourself. ```js import HSTabs from "@preline/tabs/non-auto"; HSTabs.autoInit(); // Or initialize a specific element manually const el = document.querySelector("#tabs"); if (el) new HSTabs(el); ``` ### TypeScript This package ships with TypeScript type definitions. No additional `@types/` package is needed. ## Basic usage The following example demonstrates the minimal HTML structure required for a tabs component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The example shows three tabs with corresponding content panels, with the first tab active by default. ```html <nav class="flex gap-x-2" aria-label="Tabs" role="tablist"> <button type="button" class="active" id="hs-unstyled-tabs-item-first" aria-selected="true" data-hs-tab="#hs-unstyled-tabs-first" aria-controls="hs-unstyled-tabs-first" role="tab"> Tab 1 </button> <button type="button" id="hs-unstyled-tabs-item-second" aria-selected="false" data-hs-tab="#hs-unstyled-tabs-second" aria-controls="hs-unstyled-tabs-second" role="tab"> Tab 2 </button> <button type="button" id="hs-unstyled-tabs-item-third" aria-selected="false" data-hs-tab="#hs-unstyled-tabs-third" aria-controls="hs-unstyled-tabs-third" role="tab"> Tab 3 </button> </nav> <div class="mt-3"> <div id="hs-unstyled-tabs-first" role="tabpanel" aria-labelledby="hs-unstyled-tabs-item-first"> This is the <em>first</em> item's tab body. </div> <div id="hs-unstyled-tabs-second" class="hidden" role="tabpanel" aria-labelledby="hs-unstyled-tabs-item-second"> This is the <em>second</em> item's tab body. </div> <div id="hs-unstyled-tabs-third" class="hidden" role="tabpanel" aria-labelledby="hs-unstyled-tabs-item-third"> This is the <em>third</em> item's tab body. </div> </div> ``` **Structure Requirements:** - `role="tablist"`: Required on the container element (nav, div, etc.) - `role="tab"`: Required on each tab button - `role="tabpanel"`: Required on each content panel - `data-hs-tab`: Required on each tab button, must be a valid CSS selector pointing to the corresponding tabpanel - Unique `id` attributes for each tab button and its corresponding panel - Proper ARIA attributes (`aria-selected`, `aria-controls`, `aria-labelledby`) **Initial State:** - To have a tab active by default, add the `active` class to the tab button and set `aria-selected="true"` - For inactive tabs, add the `hidden` class to the tabpanel and set `aria-selected="false"` ## Accessibility notes ### Keyboard interactions | Command | Description | | --- | --- | | ArrowLeft / ArrowRight | Selects the previous/next non-disabled tab. | | ArrowUp / ArrowDown (in vertical mode) | Selects the previous/next non-disabled tab. | | Home / End | Selects the first/last non-disabled tab. | | Enter | Activates the selected tab. | ## Configuration Options ### Data Attributes Data attributes are added directly to HTML elements to configure tab behavior. | Attribute | Target Element | Type | Default | Description | | --- | --- | --- | --- | --- | | `data-hs-tabs` | Tablist container | object (JSON) | - | Contains configuration options for customizing tab behavior and appearance. | | `:eventType` | Inside `data-hs-tabs` | `"click"` \| `"hover"` | `"click"` | Set `hover` to activate tabs on mouseover, or `click` for manual clicks (the default). | | `data-hs-tab` | Tab button (trigger) | string (CSS selector) | - | Activate a tab by specifying the selector of the target tabpanel. This must be a valid CSS selector pointing to the tabpanel element. | | `data-hs-tab-select` | Tablist container | string (ID) | - | You can pass a select ID there. Each option of this select must have a value equal to the tab ID (e.g., `<option value="#hs-tab-to-select-first">Tab 1</option>`). When you select this value, the corresponding tab will be opened. | **Example:** ```html <nav data-hs-tabs='{"eventType": "hover"}' aria-label="Tabs" role="tablist"> <button data-hs-tab="#hs-tab-first" role="tab">Tab 1</button> </nav> ``` ### Tailwind Modifiers | Name | Description | | --- | --- | | `hs-tab-active:*` | A modifier that allows you to set Tailwind classes when the tab is active. Can be applied to both the toggle button and the content panel. | ## JavaScript API The `HSTabs` object is available in the global `window` object after the plugin is loaded. ### Instance Methods These methods are called on a tabs instance. | Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | `destroy()` | None | `void` | Destroys the tabs instance, removes all generated markup, classes, and event listeners. Use when removing tabs from DOM. | ### Static Methods These methods are called directly on the `HSTabs` class. | Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | `HSTabs.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HSTabs \| { id: string \| number, element: HSTabs } \| null` | Returns the tabs instance associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSTabs` instance. If `isInstance` is `false` or omitted, returns the `HSTabs` instance directly. Returns `null` if tabs instance is not found. | | `HSTabs.open(target)` | `target`: `HTMLElement` | `void` | Opens the tab identified by target. The target should be a tab button element. Static method to programmatically switch tabs. | ### Usage Examples **Example 1: Destroying tabs instance** ```javascript const instance = HSTabs.getInstance('#hs-tabs', true); if (instance) { const { element } = instance; const destroyBtn = document.querySelector('#hs-destroy-btn'); destroyBtn.addEventListener('click', () => { element.destroy(); }); } ``` **Example 2: Opening tab programmatically (static method)** ```javascript const openBtn = document.querySelector('#hs-open-btn'); openBtn.addEventListener('click', () => { const tabButton = document.querySelector('#hs-tab-first'); if (tabButton) { HSTabs.open(tabButton); } }); ``` **Example 3: Getting instance and using methods (recommended pattern)** ```javascript // Get the tabs instance const instance = HSTabs.getInstance('#hs-tabs', true); if (instance) { const { element } = instance; // Access instance properties console.log('Current tab:', element.current); console.log('Current content:', element.currentContent); // Clean up when removing from DOM function removeTabs() { element.destroy(); } } ``` ## Events Tabs instances emit events that can be listened to for lifecycle hooks and custom behavior. | Event Name | When Fired | Callback Parameter | Description | | --- | --- | --- | --- | | `on:change` | When any tab is changed | `{ el: HTMLElement, prev: string, current: string }` | Fires when a tab is switched. Returns an object with:<br>- `el`: The toggle button element that was clicked<br>- `prev`: Previous tab ID<br>- `current`: Current tab ID | ### Event Usage Example ```javascript // Get tabs instance const instance = HSTabs.getInstance('#hs-tabs', true); if (instance) { const { element } = instance; // Listen to change event element.on('change', ({ el, prev, current }) => { console.log('Tab changed:', { clickedButton: el, previousTab: prev, currentTab: current }); // Perform actions after tab changes // e.g., load content, update UI, track analytics }); } ``` ## Common Patterns ### Pattern 1: Hover Activation Activate tabs on hover instead of click. ```html <nav data-hs-tabs='{"eventType": "hover"}' aria-label="Tabs" role="tablist"> <button data-hs-tab="#hs-tab-first" role="tab">Tab 1</button> <button data-hs-tab="#hs-tab-second" role="tab">Tab 2</button> </nav> ``` ### Pattern 2: Programmatic Control Control tabs from external buttons. ```html <nav id="hs-tabs-first" aria-label="Tabs" role="tablist"> <button data-hs-tab="#hs-tab-content-first" role="tab">Tab 1</button> <button data-hs-tab="#hs-tab-content-second" role="tab">Tab 2</button> </nav> <button id="hs-open-tab-first">Open Tab 1</button> <button id="hs-open-tab-second">Open Tab 2</button> <script> document.querySelector('#hs-open-tab-first').addEventListener('click', () => { const tabButton = document.querySelector('[data-hs-tab="#hs-tab-content-first"]'); if (tabButton) { HSTabs.open(tabButton); } }); document.querySelector('#hs-open-tab-second').addEventListener('click', () => { const tabButton = document.querySelector('[data-hs-tab="#hs-tab-content-second"]'); if (tabButton) { HSTabs.open(tabButton); } }); </script> ``` ## License Copyright (c) 2026 Preline Labs. Licensed under the [MIT License](https://opensource.org/licenses/MIT).