npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@preline/tabs

v4.2.0

Published

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

Readme

Tabs

Tabs make it easy to switch between different views.

npm License: MIT Demo

Contents

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.

npm i @preline/tabs

CSS

Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.

@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:

<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.

<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.

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.

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.

<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:

<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)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

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)

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)

// 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:- el: The toggle button element that was clicked- prev: Previous tab ID- current: Current tab ID |

Event Usage Example

// 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.

<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.

<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.