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

@get-set/gs-tabs

v1.0.2

Published

Get-Set Tabs

Readme

GSTabs

A dependency-free, feature-rich tabs / tab-panels component available in four flavours from one codebase:

  • Native / vanilla JS — a window.GSTabs(selector | element, params) factory plus a window.GSTabsConfigue instance registry.
  • jQuery$(selector).GSTabs(params) (auto-registered when jQuery is present).
  • Prototypeelement.GSTabs(params) on any HTMLElement.
  • React — a <GSTabs /> component with a typed imperative ref handle.

All four share the exact same engine (actions/, constants/, helpers/, types/), so behaviour is identical across targets.

Features

  • 5 visual variantsline, underline, pill, enclosed, segment.
  • Animated active-indicator that smoothly slides between tabs (line / underline).
  • Orientation horizontal / vertical and tabPosition top / bottom / left / right (left/right imply vertical).
  • 8 panel transitionsnone, fade, slide, slide-up, slide-down, scale, fade-scale, flip — with tunable duration + easing, all honoring prefers-reduced-motion.
  • Controlled + uncontrolled active tab (activeTab / defaultActiveTab, by id or index).
  • Lazy panels (lazy) that mount on first activation, with optional keepMounted.
  • Editable tabsclosable (per-tab × button) and addable (+ button with onAdd).
  • Draggable reorder of tabs.
  • Per-tab icon, badge, disabled, closable.
  • Overflow handling when tabs exceed the width — scroll (prev/next buttons), menu, wrap, none.
  • Alignmentstart / center / end / stretch / justify (plus a stretch shorthand).
  • Full keyboard navigation — Arrow keys (orientation + RTL aware), Home/End, Enter/Space, with a roving tabindex.
  • ARIA — proper tablist / tab / tabpanel roles, aria-selected, aria-controls, aria-labelledby, aria-orientation.
  • Theminglight / dark / auto (follows OS) plus a custom accent color token.
  • RTL layout, 3 size presets (sm / md / lg), per-part customClass overrides.
  • Two data sources — a tabs config array or markup children carrying data-gs-* attributes.
  • Lifecycle callbacksbeforeChange, onChange, onClose, onAdd, onReorder.
  • React-only gsx prop for scoped inline styles.

Installation

npm i @get-set/gs-tabs

Compatibility

| Target | Requirement | |---|---| | React (the <GSTabs> component) | React 16.8+ (Hooks), and 17 / 18 / 19. React is an optional peer dependency — you only need it for the component. | | Native / jQuery / Prototype (window.GSTabs) | No framework. Any modern evergreen browser. | | TypeScript | First-class — type declarations (.d.ts) ship in the package. | | SSR / Next.js | Safe to import server-side (no DOM access at module load). Render the component inside a Client Component ('use client'). |

Package entry points

From package.json:

| Field | Value | |---|---| | name | @get-set/gs-tabs | | main | dist/components/GSTabs.js | | module | dist/components/GSTabs.js | | types | dist/components/GSTabs.d.ts | | exports['.'].import | ./dist/components/GSTabs.js (React / ESM) | | exports['.'].require | ./dist-js/bundle.js (native window bundle) | | files | dist, dist-js, styles, example.html |

Project layout

GSTabs/
├─ GSTabs.ts                    # native window.GSTabs factory (entry)
├─ actions/                     # init / setActive / add / close / destroy / refresh …
├─ constants/                   # animations, variants, sizes, defaultParams
├─ helpers/                     # tabs, layout, keyboard, indicator, draggable, animate
├─ types/                       # params, ref, global.d.ts
├─ components/
│  ├─ GSTabs.tsx                # React <GSTabs> component
│  └─ styles/                   # GSTabs.css / .scss / GSTabsCSS.ts (bundled string)
├─ styles/                      # GSTabs.css / .scss (shippable stylesheet)
└─ example.html                 # native showcase

The stylesheet is kept in 5 synced sources (styles/GSTabs.css, styles/GSTabs.scss, components/styles/GSTabs.css, components/styles/GSTabs.scss, components/styles/GSTabsCSS.ts). The React component injects GSTabsCSS.ts automatically; for the native / jQuery / prototype targets, include styles/GSTabs.css yourself.


Vanilla (window factory)

The factory accepts a CSS selector string OR a DOM element as its first argument, then a params object.

<link rel="stylesheet" href="node_modules/@get-set/gs-tabs/styles/GSTabs.css" />
<script src="node_modules/@get-set/gs-tabs/dist-js/bundle.js"></script>

<div id="tabs"></div>

<script>
  // selector string …
  const tabs = window.GSTabs('#tabs', {
    reference: 'main',
    variant: 'underline',
    animation: 'slide',
    tabs: [
      { id: 'home', label: 'Home', content: '<p>Welcome home.</p>' },
      { id: 'profile', label: 'Profile', badge: 3, content: '<p>Your profile.</p>' },
      { id: 'settings', label: 'Settings', content: '<p>Settings.</p>', disabled: false }
    ],
    onChange: (id, prev) => console.log('changed', prev, '→', id)
  });

  // … OR an element (both are supported):
  const el = document.getElementById('tabs');
  // window.GSTabs(el, { … });

  tabs.setActive('profile');
  tabs.next();
  console.log(tabs.getActive());
</script>

Markup (data-attribute) mode

Instead of a tabs array, describe tabs with data-gs-tab children:

<div id="docs">
  <div data-gs-tab data-gs-label="Overview" data-gs-id="ov">
    <p>Overview content…</p>
  </div>
  <div data-gs-tab data-gs-label="API" data-gs-id="api" data-gs-badge="new">
    <p>API content…</p>
  </div>
  <div data-gs-tab data-gs-label="Legacy" data-gs-id="legacy" data-gs-disabled>
    <p>Legacy content…</p>
  </div>
</div>
<script>window.GSTabs('#docs', { variant: 'pill' });</script>

Supported data attributes: data-gs-tab (marks a tab), data-gs-label, data-gs-id, data-gs-icon, data-gs-badge, data-gs-disabled, data-gs-closable.

The instance registry

window.GSTabs('#tabs', { reference: 'main', tabs: [...] });
const instance = window.GSTabsConfigue.instance('main');
instance.setActive(1);

jQuery

When jQuery is present on the page, $.fn.GSTabs is registered automatically by the bundle:

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="node_modules/@get-set/gs-tabs/dist-js/bundle.js"></script>

<div class="tabs"></div>
<script>
  $('.tabs').GSTabs({
    variant: 'segment',
    tabs: [
      { id: 'a', label: 'Day', content: '<p>Day view</p>' },
      { id: 'b', label: 'Week', content: '<p>Week view</p>' },
      { id: 'c', label: 'Month', content: '<p>Month view</p>' }
    ]
  });
</script>

$('.tabs') may match multiple elements — each is initialized independently.


Prototype

Every HTMLElement gets a GSTabs method (also registered by the bundle):

<script src="node_modules/@get-set/gs-tabs/dist-js/bundle.js"></script>
<div id="tabs"></div>
<script>
  document.getElementById('tabs').GSTabs({
    variant: 'enclosed',
    tabPosition: 'left',
    tabs: [
      { id: 'g', label: 'General', content: '<p>General</p>' },
      { id: 's', label: 'Security', content: '<p>Security</p>' }
    ]
  });
</script>

Both the jQuery and prototype adapters call new window.GSTabs(this, params) — passing the element (not a selector). The factory accepts an element as its first argument precisely so these adapters work.


React

'use client';
import { useRef } from 'react';
import GSTabs, { GSTabsHandle } from '@get-set/gs-tabs';

export default function Example() {
  const ref = useRef<GSTabsHandle>(null);

  return (
    <>
      <GSTabs
        ref={ref}
        reference="main"
        variant="underline"
        animation="slide"
        defaultActiveTab="home"
        onChange={(id, prev) => console.log(prev, '→', id)}
        tabs={[
          { id: 'home', label: 'Home', content: <p>Welcome home.</p> },
          { id: 'profile', label: 'Profile', badge: 3, content: <p>Your profile.</p> },
          { id: 'settings', label: 'Settings', content: <p>Settings.</p> }
        ]}
      />
      <button onClick={() => ref.current?.next()}>Next</button>
      <button onClick={() => ref.current?.setActive('profile')}>Go to profile</button>
    </>
  );
}

You can also render tabs from children with data-gs-tab:

<GSTabs variant="pill">
  <div data-gs-tab data-gs-label="One">
    <p>Panel one</p>
  </div>
  <div data-gs-tab data-gs-label="Two" data-gs-badge="new">
    <p>Panel two</p>
  </div>
</GSTabs>

For rich labels/content in config mode, use labelNode / contentNode / iconNode:

<GSTabs
  tabs={[
    { id: 'x', labelNode: <strong>Bold</strong>, contentNode: <MyPanel /> }
  ]}
/>

The imperative handle (GSTabsHandle)

| Method | Signature | Description | |---|---|---| | setActive | (idOrIndex: string \| number) => void | Activate a tab by id or index. | | next | () => void | Activate the next enabled tab (wraps). | | prev | () => void | Activate the previous enabled tab (wraps). | | getActive | () => string \| null | The currently active tab id. | | add | (tab?: GSTabsItem, activate?: boolean) => string \| undefined | Add a tab (optionally activate). Returns its id. | | close | (idOrIndex: string \| number) => void | Close (remove) a tab. | | refresh | () => void | Re-measure the indicator / overflow. | | destroy | () => void | Remove all tabs (uncontrolled teardown). |

The gsx prop (React only)

Scoped inline styles that are injected into <head> for this instance only (scoped via [data-key]) and removed on unmount:

<GSTabs
  gsx={{ '.gs-tabs-tab': { fontWeight: '600' }, '.gs-tabs-indicator': { height: '4px' } }}
  tabs={[...]}
/>

Native imperative API

The window.GSTabs(...) factory returns a ref with the same actions as the React handle:

| Method | Description | |---|---| | setActive(idOrIndex) | Activate a tab by id or index. | | next() | Activate the next enabled tab (wraps). | | prev() | Activate the previous enabled tab (wraps). | | getActive() | The currently active tab id (or null). | | add(tab?, activate?) | Add a tab (optionally activate). Returns its id. | | close(idOrIndex) | Close (remove) a tab. | | refresh() | Rebuild from the current params, preserving the active tab. | | destroy() | Tear down and empty the root, unregistering the instance. |


Props

Every option (native params & React props share the same names):

| Prop | Type | Default | Description | |---|---|---|---| | reference | string | auto GUID | Stable registry key. | | tabs | GSTabConfig[] | undefined | Tab definitions. When omitted, tabs are read from data-gs-tab markup. | | activeTab | string \| number | undefined | Controlled active tab (id or index). | | defaultActiveTab | string \| number | first enabled | Uncontrolled initial active tab. | | orientation | 'horizontal' \| 'vertical' | 'horizontal' | Tablist axis. | | tabPosition | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | Tablist placement (left/right imply vertical). | | variant | 'line' \| 'underline' \| 'pill' \| 'enclosed' \| 'segment' | 'line' | Visual variant. | | size | 'sm' \| 'md' \| 'lg' | 'md' | Size preset. | | align | 'start' \| 'center' \| 'end' \| 'stretch' \| 'justify' | 'start' | Tab distribution. | | stretch | boolean | false | Shorthand for align: 'stretch'. | | lazy | boolean | false | Mount a panel only on first activation. | | keepMounted | boolean | true | Keep lazily-mounted panels after deactivation. | | animation | GSTabsAnimation \| false | 'fade' | Panel transition (false disables). | | animationDuration | number \| { enter?: number } | 260 | Transition duration in ms. | | animationEasing | string | cubic-bezier(.4,0,.2,1) | Transition + indicator easing. | | animatedIndicator | boolean | true | Animate the sliding indicator bar. | | reducedMotion | 'auto' \| boolean | 'auto' | Honor prefers-reduced-motion. | | closable | boolean | false | Show a × on every tab (per-tab closable overrides). | | addable | boolean | false | Show a trailing + button. | | addButtonLabel | string | '+' | Add button label. | | draggable | boolean | false | Reorder tabs by dragging. | | overflow | 'scroll' \| 'menu' \| 'wrap' \| 'none' | 'scroll' | Overflow handling. | | theme | 'light' \| 'dark' \| 'auto' | 'auto' | Visual theme. | | accent | string | #2563eb | Accent color (CSS var --gst-accent). | | rtl | boolean | false | Right-to-left layout. | | customClass | GSTabsCustomClass | undefined | Per-part class overrides. | | className | string | undefined | Extra class on the root. | | gsx | NestedCSS | undefined | React only. Scoped inline styles. | | beforeChange | (nextId, prevId) => void \| boolean | — | Return false to cancel a change. | | onChange | (id, prevId) => void | — | Fired after the active tab changes. | | onClose | (id) => void | — | Fired when a tab is closed. | | onAdd | () => GSTabConfig \| void | — | Fired by the + button; may return a new tab. | | onReorder | (from, to) => void | — | Fired after a drag reorder. |

GSTabConfig (a single tab)

| Field | Type | Description | |---|---|---| | id | string | Stable id (auto-generated from the label when omitted). | | label | string | Tab label (HTML string for native). | | labelNode | ReactNode | React only. Rich label (takes precedence over label). | | content | string | Panel content (HTML string for native). | | contentNode | ReactNode | React only. Rich panel content. | | icon | string | Leading icon (HTML string). | | iconNode | ReactNode | React only. Rich icon. | | badge | string \| number | Badge shown after the label. | | disabled | boolean | Disable the tab (skipped in keyboard nav). | | closable | boolean | Show a × on this tab. | | className | string | Extra class on the tab button. |

customClass parts

root, tablist, tab, activeTab, panel, indicator, addButton, scrollButton.


Catalogs

Variants

| Variant | Look | |---|---| | line | Rail under the tablist + a thin sliding accent bar. | | underline | A thicker sliding underline, no rail. | | pill | Rounded, filled active tab. | | enclosed | Card-like active tab joined to the panel. | | segment | iOS-style segmented control on a tinted track. |

Panel animations

none, fade, slide, slide-up, slide-down, scale, fade-scale, flip.

Sizes

sm, md, lg.

Overflow modes

| Mode | Behaviour | |---|---| | scroll | Prev/next scroll buttons appear when tabs overflow. | | menu | Overflow tabs collapse into a dropdown (styling hook). | | wrap | Tabs wrap to multiple rows. | | none | Overflow is clipped. |


Keyboard support

| Key | Action | |---|---| | ArrowRight / ArrowLeft | Move focus (horizontal). RTL-aware. | | ArrowDown / ArrowUp | Move focus (vertical). | | Home / End | First / last enabled tab. | | Enter / Space | Activate the focused tab. | | Tab | Enters/leaves the tablist (roving tabindex — only the active tab is tabbable). |

Focus follows selection (automatic activation). Disabled tabs are skipped.

License

ISC © Get-Set