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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@atom_design/tabs

v1.0.0

Published

A flexible React Native Tabs component with multiple style variants, sizes, badges, and scrollable support.

Readme

@atom_design/tabs

A highly customizable, accessible React Native Tabs component with multiple style variants, sizes, badges, icons, and scrollable support.

Features

  • 🎨 6 Variants: allRadius, leftRightRadius, noRadius, roundedRadius, dualLineTopRadius, underline
  • 📏 3 Sizes: small, medium, large
  • 🔢 Badges: Built-in badge support with custom rendering
  • 🎯 Icons: Custom icon support for each tab
  • 📜 Scrollable: Horizontal scroll for many tabs
  • Accessible: Full accessibility support
  • 🎯 TypeScript: Full TypeScript definitions included
  • 🎨 Customizable: Style every part of the tabs

Installation

npm install @atom_design/tabs
# or
yarn add @atom_design/tabs

Peer Dependencies

npm install react react-native prop-types

Usage

Basic Usage

import React, { useState } from 'react';
import Tabs from '@atom_design/tabs';

const App = () => {
  const [activeTab, setActiveTab] = useState('1');

  const tabs = [
    { id: '1', name: 'Home' },
    { id: '2', name: 'Profile' },
    { id: '3', name: 'Settings' },
  ];

  return (
    <Tabs
      tabs={tabs}
      activeTab={activeTab}
      onTabChange={setActiveTab}
    />
  );
};

Variants

// All corners rounded (default)
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} variant="allRadius" />

// Only first and last tabs rounded
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} variant="leftRightRadius" />

// No border radius
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} variant="noRadius" />

// Fully rounded pill shape
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} variant="roundedRadius" />

// Top corners rounded
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} variant="dualLineTopRadius" />

// Underline style
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} variant="underLineTabBackground" />

Sizes

<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} size="small" />
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} size="medium" />
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} size="large" />

With Badges

const tabsWithBadges = [
  { id: '1', name: 'Inbox', badge: 5 },
  { id: '2', name: 'Updates', badge: 12 },
  { id: '3', name: 'Archive', badge: 0 },
];

<Tabs
  tabs={tabsWithBadges}
  activeTab={activeTab}
  onTabChange={setActiveTab}
  showBadge={true}
/>

With Icons

import Icon from 'react-native-vector-icons/MaterialIcons';

<Tabs
  tabs={tabs}
  activeTab={activeTab}
  onTabChange={setActiveTab}
  renderIcon={(tab, isActive) => (
    <Icon
      name={tab.icon}
      size={18}
      color={isActive ? '#fff' : '#666'}
    />
  )}
/>

Scrollable Tabs

const manyTabs = [
  { id: '1', name: 'Tab 1' },
  { id: '2', name: 'Tab 2' },
  { id: '3', name: 'Tab 3' },
  { id: '4', name: 'Tab 4' },
  { id: '5', name: 'Tab 5' },
  { id: '6', name: 'Tab 6' },
];

<Tabs
  tabs={manyTabs}
  activeTab={activeTab}
  onTabChange={setActiveTab}
  scrollable={true}
/>

Custom Colors

<Tabs
  tabs={tabs}
  activeTab={activeTab}
  onTabChange={setActiveTab}
  activeColor="#007AFF"
  activeBackgroundColor="#007AFF"
  inactiveColor="#888"
  inactiveBackgroundColor="#e0e0e0"
/>

Custom Styling

<Tabs
  tabs={tabs}
  activeTab={activeTab}
  onTabChange={setActiveTab}
  containerStyle={{ borderRadius: 12, padding: 6 }}
  tabStyle={{ paddingVertical: 14 }}
  activeTabStyle={{ shadowOpacity: 0.2 }}
  textStyle={{ fontWeight: '500' }}
  activeTextStyle={{ fontWeight: 'bold' }}
/>

Disabled State

// Disable all tabs
<Tabs tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} disabled={true} />

// Disable individual tabs
const tabsWithDisabled = [
  { id: '1', name: 'Active' },
  { id: '2', name: 'Disabled', disabled: true },
  { id: '3', name: 'Active' },
];
<Tabs tabs={tabsWithDisabled} activeTab={activeTab} onTabChange={setActiveTab} />

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | tabs | TabItem[] | [] | Array of tab items (required) | | activeTab | string \| number | - | Currently active tab ID | | onTabChange | (tabId) => void | - | Callback when tab changes | | variant | TabVariant | 'allRadius' | Visual style variant | | size | 'small' \| 'medium' \| 'large' | 'medium' | Tab size | | disabled | boolean | false | Disable all tabs | | scrollable | boolean | false | Enable horizontal scrolling | | showBadge | boolean | false | Show badges on tabs | | activeColor | string | '#d9232d' | Active text/border color | | inactiveColor | string | '#666' | Inactive text color | | activeBackgroundColor | string | '#d9232d' | Active background color | | inactiveBackgroundColor | string | '#f0f0f0' | Container background color | | containerStyle | StyleProp<ViewStyle> | - | Container style | | tabStyle | StyleProp<ViewStyle> | - | Each tab style | | activeTabStyle | StyleProp<ViewStyle> | - | Active tab style | | textStyle | StyleProp<TextStyle> | - | Text style | | activeTextStyle | StyleProp<TextStyle> | - | Active text style | | badgeStyle | StyleProp<ViewStyle> | - | Badge style | | renderIcon | (tab, isActive) => ReactNode | - | Custom icon renderer | | renderBadge | (tab, isActive) => ReactNode | - | Custom badge renderer | | testID | string | - | Test ID for testing |

TabItem Interface

| Property | Type | Required | Description | |----------|------|----------|-------------| | id | string \| number | Yes | Unique identifier | | name | string | Yes | Display name | | badge | string \| number | No | Badge value | | disabled | boolean | No | Disable this tab | | accessibilityLabel | string | No | Custom a11y label |

Available Variants

| Variant | Description | |---------|-------------| | allRadius | All tabs have rounded corners (default) | | leftRightRadius | Only first and last tabs have rounded corners | | noRadius | No border radius on tabs | | roundedRadius | Fully rounded pill-shaped tabs | | dualLineTopRadius | Top corners rounded, good for card headers | | underLineTabBackground | Underline-style tabs with bottom indicator |

Accessibility

The Tabs component is fully accessible:

  • Uses accessibilityRole="tab" for each tab
  • Uses accessibilityRole="tablist" for container
  • Announces selected state via accessibilityState
  • Reports disabled state
  • Provides position hint ("Tab 1 of 3")

Full Test Screen Example

Copy this complete screen to test all tabs variations in your app:

import React, { useState } from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';
import Tabs from '@atom_design/tabs';
// Optional: for custom icons
// import Icon from 'react-native-vector-icons/MaterialIcons';

const TabsTestScreen = () => {
  const [activeTab1, setActiveTab1] = useState('1');
  const [activeTab2, setActiveTab2] = useState('1');
  const [activeTab3, setActiveTab3] = useState('1');
  const [activeTab4, setActiveTab4] = useState('1');
  const [activeTab5, setActiveTab5] = useState('1');
  const [activeTab6, setActiveTab6] = useState('1');
  const [activeTab7, setActiveTab7] = useState('1');
  const [activeTab8, setActiveTab8] = useState('1');
  const [activeTab9, setActiveTab9] = useState('1');
  const [activeTab10, setActiveTab10] = useState('1');
  const [activeTab11, setActiveTab11] = useState('1');
  const [activeTab12, setActiveTab12] = useState('1');

  // Basic tabs
  const basicTabs = [
    { id: '1', name: 'Home' },
    { id: '2', name: 'Profile' },
    { id: '3', name: 'Settings' },
  ];

  // Tabs with badges
  const badgeTabs = [
    { id: '1', name: 'Inbox', badge: 5 },
    { id: '2', name: 'Updates', badge: 23 },
    { id: '3', name: 'Spam', badge: 100 },
  ];

  // Many tabs for scrollable
  const manyTabs = [
    { id: '1', name: 'Overview' },
    { id: '2', name: 'Analytics' },
    { id: '3', name: 'Reports' },
    { id: '4', name: 'Users' },
    { id: '5', name: 'Settings' },
    { id: '6', name: 'Help' },
  ];

  // Tabs with disabled
  const mixedTabs = [
    { id: '1', name: 'Active' },
    { id: '2', name: 'Disabled', disabled: true },
    { id: '3', name: 'Active' },
  ];

  // Two tabs
  const twoTabs = [
    { id: '1', name: 'Option A' },
    { id: '2', name: 'Option B' },
  ];

  return (
    <ScrollView style={styles.container} contentContainerStyle={styles.content}>
      <Text style={styles.title}>@atom_design/tabs</Text>
      <Text style={styles.subtitle}>Complete Component Test</Text>

      {/* VARIANTS SECTION */}
      <Text style={styles.sectionTitle}>Variants</Text>

      <Text style={styles.label}>All Radius (Default)</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab1}
        onTabChange={setActiveTab1}
        variant="allRadius"
      />

      <Text style={styles.label}>Left Right Radius</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab2}
        onTabChange={setActiveTab2}
        variant="leftRightRadius"
      />

      <Text style={styles.label}>No Radius</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab3}
        onTabChange={setActiveTab3}
        variant="noRadius"
      />

      <Text style={styles.label}>Rounded Radius (Pill)</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab4}
        onTabChange={setActiveTab4}
        variant="roundedRadius"
      />

      <Text style={styles.label}>Dual Line Top Radius</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab5}
        onTabChange={setActiveTab5}
        variant="dualLineTopRadius"
      />

      <Text style={styles.label}>Underline Style</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab6}
        onTabChange={setActiveTab6}
        variant="underLineTabBackground"
      />

      {/* SIZES SECTION */}
      <Text style={styles.sectionTitle}>Sizes</Text>

      <Text style={styles.label}>Small</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab7}
        onTabChange={setActiveTab7}
        size="small"
      />

      <Text style={styles.label}>Medium (Default)</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab7}
        onTabChange={setActiveTab7}
        size="medium"
      />

      <Text style={styles.label}>Large</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab7}
        onTabChange={setActiveTab7}
        size="large"
      />

      {/* BADGES SECTION */}
      <Text style={styles.sectionTitle}>With Badges</Text>
      <Tabs
        tabs={badgeTabs}
        activeTab={activeTab8}
        onTabChange={setActiveTab8}
        showBadge={true}
      />

      <Text style={styles.label}>Underline with Badges</Text>
      <Tabs
        tabs={badgeTabs}
        activeTab={activeTab8}
        onTabChange={setActiveTab8}
        variant="underLineTabBackground"
        showBadge={true}
      />

      {/* SCROLLABLE SECTION */}
      <Text style={styles.sectionTitle}>Scrollable Tabs</Text>
      <Tabs
        tabs={manyTabs}
        activeTab={activeTab9}
        onTabChange={setActiveTab9}
        scrollable={true}
      />

      {/* CUSTOM COLORS SECTION */}
      <Text style={styles.sectionTitle}>Custom Colors</Text>

      <Text style={styles.label}>Blue Theme</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab10}
        onTabChange={setActiveTab10}
        activeColor="#007AFF"
        activeBackgroundColor="#007AFF"
        inactiveBackgroundColor="#e8f0fe"
      />

      <Text style={styles.label}>Green Theme</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab10}
        onTabChange={setActiveTab10}
        activeColor="#34C759"
        activeBackgroundColor="#34C759"
        inactiveBackgroundColor="#e8f8ec"
      />

      <Text style={styles.label}>Purple Underline</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab10}
        onTabChange={setActiveTab10}
        variant="underLineTabBackground"
        activeColor="#AF52DE"
      />

      {/* DISABLED SECTION */}
      <Text style={styles.sectionTitle}>Disabled States</Text>

      <Text style={styles.label}>Mixed Enabled/Disabled</Text>
      <Tabs
        tabs={mixedTabs}
        activeTab={activeTab11}
        onTabChange={setActiveTab11}
      />

      <Text style={styles.label}>All Disabled</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab11}
        onTabChange={setActiveTab11}
        disabled={true}
      />

      {/* CUSTOM STYLING SECTION */}
      <Text style={styles.sectionTitle}>Custom Styling</Text>

      <Text style={styles.label}>Custom Container & Tabs</Text>
      <Tabs
        tabs={basicTabs}
        activeTab={activeTab12}
        onTabChange={setActiveTab12}
        containerStyle={styles.customContainer}
        tabStyle={styles.customTab}
        activeTabStyle={styles.customActiveTab}
        textStyle={styles.customText}
        activeTextStyle={styles.customActiveText}
      />

      <Text style={styles.label}>Rounded with Shadow</Text>
      <Tabs
        tabs={twoTabs}
        activeTab={activeTab12}
        onTabChange={setActiveTab12}
        variant="roundedRadius"
        containerStyle={styles.shadowContainer}
        activeTabStyle={styles.shadowActiveTab}
      />

      {/* TWO TABS SECTION */}
      <Text style={styles.sectionTitle}>Two Tabs (Toggle Style)</Text>
      <Tabs
        tabs={twoTabs}
        activeTab={activeTab12}
        onTabChange={setActiveTab12}
        variant="roundedRadius"
      />

      <View style={{ height: 50 }} />
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  content: {
    padding: 20,
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    textAlign: 'center',
    marginBottom: 5,
    color: '#333',
  },
  subtitle: {
    fontSize: 16,
    textAlign: 'center',
    marginBottom: 30,
    color: '#666',
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    marginTop: 30,
    marginBottom: 15,
    color: '#333',
    borderBottomWidth: 1,
    borderBottomColor: '#ddd',
    paddingBottom: 5,
  },
  label: {
    fontSize: 14,
    color: '#666',
    marginBottom: 8,
    marginTop: 15,
  },

  // Custom styling examples
  customContainer: {
    borderRadius: 12,
    padding: 6,
    backgroundColor: '#1a1a2e',
  },
  customTab: {
    paddingVertical: 12,
  },
  customActiveTab: {
    backgroundColor: '#e94560',
    borderRadius: 10,
  },
  customText: {
    color: '#888',
    fontWeight: '500',
  },
  customActiveText: {
    color: '#fff',
    fontWeight: 'bold',
  },

  shadowContainer: {
    backgroundColor: '#fff',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  shadowActiveTab: {
    shadowColor: '#d9232d',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.3,
    shadowRadius: 4,
    elevation: 4,
  },
});

export default TabsTestScreen;

Usage in Your App

// App.js or navigation screen
import TabsTestScreen from './TabsTestScreen';

// In your navigator or directly
<TabsTestScreen />

License

MIT © Atom Design