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

@fvc/tabs

v1.1.0

Published

`@fvc/tabs` provides FE-VIS styled tabs on top of Ant Design. It preserves Ant Design's tablist, tabpanel, keyboard, focus, and panel-mounting behavior while applying the AVIS UI kit pill design.

Downloads

1,860

Readme

@fvc/tabs

@fvc/tabs provides FE-VIS styled tabs on top of Ant Design. It preserves Ant Design's tablist, tabpanel, keyboard, focus, and panel-mounting behavior while applying the AVIS UI kit pill design.

Installation

bun add @fvc/tabs

Peer Dependencies

bun add react antd

The draggable prop additionally requires @dnd-kit:

bun add @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities

Import

import { Tabs } from '@fvc/tabs';

Quick Start

import { useState } from 'react';
import { Tabs } from '@fvc/tabs';

const items = [
  { key: 'overview', label: 'Overview', children: <Overview /> },
  { key: 'details', label: 'Details', children: <Details /> },
  { key: 'history', label: 'History', children: <History /> },
];

export function PageHeader() {
  const [activeKey, setActiveKey] = useState('overview');

  return <Tabs items={items} activeKey={activeKey} onChange={setActiveKey} />;
}

Usage

Controlled

activeKey remains the source of truth. Clicking another tab calls onChange, but the visible tab changes only when the parent supplies a new activeKey.

<Tabs items={items} activeKey={activeKey} onChange={setActiveKey} />

Uncontrolled

<Tabs items={items} defaultActiveKey="details" />

Figma Size M (default)

Size M uses Roboto Bold at 14px/16px with 8px vertical and 12px horizontal padding. The browser computes the final item height from those values.

<Tabs items={items} size="middle" />

Figma Size L

Size L uses Roboto Bold at 20px/20px with 10px vertical and 12px horizontal padding. The browser computes the final item height from those values.

<Tabs items={items} size="large" />

Disabled Item

Disabled click and keyboard behavior remains owned by Ant Design.

<Tabs
  items={[
    { key: 'active', label: 'Active' },
    { key: 'locked', label: 'Locked', disabled: true },
  ]}
/>

Icon

icon accepts any ReactNode. The package does not require an icon library.

<Tabs
  items={[
    { key: 'home', label: 'Home', icon: <HomeIcon /> },
    { key: 'history', label: 'History', icon: <HistoryIcon /> },
  ]}
/>

Extra Content

<Tabs
  items={items}
  tabBarExtraContent={{
    left: <span>Filters</span>,
    right: <button type="button">Add</button>,
  }}
/>

Without Content Panels

Omit children when the active key controls content outside this component.

<Tabs
  items={[
    { key: 'day', label: 'Day' },
    { key: 'week', label: 'Week' },
    { key: 'month', label: 'Month' },
  ]}
  activeKey={range}
  onChange={setRange}
/>

Draggable

const [items, setItems] = useState(initialItems);

<Tabs items={items} draggable onOrderChange={setItems} />;

Enables drag-and-drop reordering via @dnd-kit — the same approach as the official Ant Design drag-and-drop tabs example. onOrderChange is called with the reordered TabItem[] after each drop; the consumer owns committing that order back into items.

Props

| Prop | Type | Default | Description | | ------------------------ | ------------------------------------------------------ | ---------- | ------------------------------------------------ | | items | AntTabsProps['items'] | - | Required tab descriptors. | | activeKey | string | - | Controlled active key. | | defaultActiveKey | string | first item | Initial uncontrolled active key. | | onChange | (key: string) => void | - | Called with the selected key. | | size | AntTabsProps['size'] | middle | Uses Ant Design size names. | | tabBarExtraContent | ReactNode \| { left?: ReactNode; right?: ReactNode } | - | Content around the tab list. | | destroyInactiveTabPane | boolean | false | Removes inactive panels when enabled. | | draggable | boolean | false | Enables drag-and-drop reordering via @dnd-kit. | | onOrderChange | (items: TabItem[]) => void | - | Called with the reordered items after each drop. | | className | string | - | Additional root class. | | style | TabsStyle | - | Root styles with typed --tabs-* variables. | | testId | string | - | Root data-testid. |

TabItem

| Field | Type | Description | | ---------- | ----------- | ------------------------------- | | key | string | Required unique key. | | label | ReactNode | Required label. | | children | ReactNode | Optional panel content. | | disabled | boolean | Prevents selection. | | icon | ReactNode | Optional icon before the label. |

Panel Mounting

Inactive panels remain mounted by default (destroyInactiveTabPane=false). This preserves form values and component state but also retains subscriptions and expensive resources. Set destroyInactiveTabPane when cleanup is more important than state preservation. Lazy code splitting remains the consumer's responsibility.

Theming

All design values are declared in src/styles/variables.scss, matching the style-file layout used by @fvc/input.

Inline overrides are type-safe:

<Tabs
  items={items}
  style={{
    '--tabs-item-active-bg-color': '#24568a',
    '--tabs-item-hover-bg-color': '#f2f2f2',
  }}
/>

Container

| Variable | Default | | ---------------------- | ------------------ | | --tabs-bg-color | var(--neutral-0) | | --tabs-border-width | 1px | | --tabs-border-color | var(--blue-250) | | --tabs-border-radius | 18px |

Item

| Variable | Default | | --------------------------- | ------------------- | | --tabs-item-padding-x | 9px | | --tabs-item-border-width | 3px | | --tabs-item-border-color | transparent | | --tabs-item-border-radius | 32px | | --tabs-item-text-color | var(--black-1000) | | --tabs-item-fw | 700 |

Selected Item

| Variable | Default | | --------------------------------- | --------------------------- | | --tabs-item-active-bg-color | var(--blue-400) | | --tabs-item-active-text-color | var(--white-text-color-0) | | --tabs-item-active-border-color | var(--gray-100) |

Hover Item

Hover is the only state sourced from the adjacent Figma <Toggles /> component because the Figma <Tabs /> variants do not expose a hover state.

| Variable | Default | | -------------------------------- | ----------------------------- | | --tabs-item-hover-bg-color | var(--gray-50) (#f2f2f2) | | --tabs-item-hover-border-color | var(--gray-100) (#fafafa) |

Size M

| Variable | Default | | ------------------------------ | -------- | | --tabs-font-family | var(--fvc-font-body, sans-serif) | | --tabs-middle-size-fz | 14px | | --tabs-middle-size-lh | 16px | | --tabs-middle-size-padding-y | 4px |

The CSS padding values compensate for the real 3px item border and 1px container border. This preserves Figma's visual 8px padding and 32px overall height.

Size L

| Variable | Default | | ----------------------------- | ------- | | --tabs-large-size-fz | 20px | | --tabs-large-size-lh | 20px | | --tabs-large-size-padding-y | 6px |

The 7px CSS padding preserves Figma's visual 10px padding and 40px overall height after the real borders are included.

Figma Mapping

The transparent base item border reserves the same space used by the selected and hover strokes. With the Figma Secondary label, two M items remain 182x32 and two L items remain 272x40.

Accessibility

The wrapper keeps Ant Design's tablist, tab, and tabpanel roles, aria-selected, aria-controls, aria-labelledby, disabled handling, keyboard navigation, and focus-visible behavior. Horizontal tabs use Left/Right; Home/End jump to the edges; Enter/Space activate the keyboard-focused tab.

Development

bun run lint
bun run type-check
bun run test
bun run build