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

@multidots/sanity-plugin-tab-block

v1.0.7

Published

A Sanity Studio plugin that lets you create tabbed content blocks with customizable styles, layouts and rich text editing capabilities.

Downloads

36

Readme

@multidots/sanity-plugin-tab-block

A comprehensive tab block plugin for Sanity Studio that provides dynamic, customizable tab interfaces with rich content support.

Features

🎯 Core Functionality

  • Multiple Tabs: Support for multiple tabs per block with validation
  • Rich Content: Portable Text support with headings, lists, links, and formatting
  • Flexible Layouts: Horizontal and vertical tab orientations with intelligent mobile adaptation
  • Responsive Design: Comprehensive responsive behavior across all device sizes
  • Full ARIA Compliance: Complete role, aria-selected, aria-controls, aria-labelledby, and tablist attributes

🎨 Customization Options

  • Layout Control: Choose between horizontal and vertical tab arrangements
  • Advanced Alignment Settings: Independent control over title, tab titles, content, and vertical alignment
  • Comprehensive Color Theming: Full color customization for all visual elements
    • Block title color
    • Tab title colors (active/inactive/hover states)
    • Tab background colors (active/inactive states)
    • Content text and background colors
    • Tab hover colors

Installation

npm install @multidots/sanity-plugin-tab-block

Quick Start

1. Add the Plugin to Your Sanity Config

import {defineConfig} from 'sanity'
import {tabBlockPlugin} from '@multidots/sanity-plugin-tab-block'

export default defineConfig({
  // ... other config
  plugins: [
    tabBlockPlugin(),
    // ... other plugins
  ],
})

2. Add to Your Schema

// In your document schema
export default defineType({
  name: 'page',
  title: 'Page',
  type: 'document',
  fields: [
    defineField({
          name: "tabBlock",
          type: "tabBlock",
    }),
  ],
})

3. Render in Your Frontend

Update GROQ Queries to Include Tab Block

export const getPageQuery = defineQuery(`
  *[_type == 'page' && slug.current == $slug][0]{
    _id,
    _type,
    name,
    slug,
    tabBlock,
  }
}`);

Create a Component Wrapper

For a clean and maintainable frontend implementation, create a dedicated component wrapper first, then use it in your pages. This approach provides better code organization and reusability.

First, create a Tab.tsx component in your components directory:

  'use client'

import { TabBlock as TabBlockComponent, TabBlockData } from "@multidots/sanity-plugin-tab-block"
  import { PortableText } from 'next-sanity'

  type TabProps = {
      tab: TabBlockData
  }

  const Tab = ({ tab }: TabProps) => {
      return (
          <TabBlockComponent
              tab={tab}
              PortableText={(props: any) => <PortableText {...props} />}
          />
      )
  }

  export default Tab

Render in Your Page Example

Use in Your Page Component

import { TabBlockData } from '@multidots/sanity-plugin-tab-block';
import Tab from '@/components/Tab'

// Add code to get the page data

export default async function Page({ params }: RouteProps) {
    const { data: page } = await getPage(params);
    return  (
        <>
            {page?.tabBlock && (
                <Tab tab={page?.tabBlock as TabBlockData} />
            )}
        </>
    ) ;
}
            

Configuration Options

Schema Fields

| Field | Type | Description | Group | |-------|------|-------------|-------| | title | string | Optional title for the entire tab block | - | | tabs | array | Array of tab objects (1-10 tabs) | Tabs & Content | | layout | string | 'horizontal' or 'vertical' | Layout & Alignment | | titleAlignment | string | 'left', 'center', or 'right' | Layout & Alignment | | tabTitleAlignment | string | 'left', 'center', or 'right' | Layout & Alignment | | tabTitleVerticalAlignment | string | 'start', 'center', or 'end' (vertical layout only) | Layout & Alignment | | tabContentAlignment | string | 'left', 'center', or 'right' | Layout & Alignment |

Color Customization

| Color Field | Description | Usage | |-------------|-------------|-------| | titleColor | Main block title color | Applied to the main title text | | tabTitleColor | Inactive tab title color | Default color for tab buttons | | tabTitleHoverColor | Tab title hover background color | Background color when hovering over tabs | | activeTabTitleColor | Active tab title color | Text color for the currently active tab | | tabBackgroundColor | Tab button background color | Default background for tab buttons | | activeTabBackgroundColor | Active tab background color | Background color for the active tab | | tabContentColor | Tab content text color | Text color within tab content areas | | tabContentBackgroundColor | Tab content area background color | Background color for the content area |

Tab Object Structure

Each tab in the tabs array contains:

{
  tabTitle: string        // Tab button text (required, 1-50 characters)
  content: PortableText[] // Rich text content (required)
}

Content Features

Supported Rich Text Elements

  • Headings: H1, H2, H3, H4
  • Text Formatting: Bold, italic, underline
  • Lists: Bulleted and numbered lists
  • Blockquotes: Quote styling

Link Configuration

Links support:

  • HTTP/HTTPS URLs
  • Email addresses (mailto:)
  • Phone numbers (tel:)

Component Props

TabBlock Component

interface TabBlockProps {
  tab: TabBlockData           // The tab block data from Sanity
  PortableText?: React.ComponentType<{value: unknown}>  // Portable Text renderer
  className?: string          // Additional CSS classes
}

TabBlockData Interface

interface TabBlockData {
  title?: string
  tabs?: Array<{
    tabTitle?: string
    content?: unknown[]
    _type?: string
    _key?: string
  }>
  layout?: 'horizontal' | 'vertical'
  titleAlignment?: 'left' | 'center' | 'right'
  tabTitleAlignment?: 'left' | 'center' | 'right'
  tabTitleVerticalAlignment?: 'start' | 'center' | 'end'
  tabContentAlignment?: 'left' | 'center' | 'right'
  // Color properties
  titleColor?: {hex: string}
  tabTitleColor?: {hex: string}
  tabTitleHoverColor?: {hex: string}
  activeTabTitleColor?: {hex: string}
  tabBackgroundColor?: {hex: string}
  activeTabBackgroundColor?: {hex: string}
  tabContentColor?: {hex: string}
  tabContentBackgroundColor?: {hex: string}
}

Styling and Customization

Responsive Design

The component automatically adapts to different screen sizes:

  • Desktop & Tablet: Maintains chosen layout (horizontal/vertical)
  • Mobile: Vertical tabs convert to horizontal scrollable navigation

Custom Styling

You can override styles by:

  1. Passing a className prop to the component
  2. Using CSS specificity to override built-in styles
  3. Customizing colors through the Sanity interface
  4. Targeting specific responsive breakpoints

CSS Classes

The component generates these CSS classes:

  • .tab-block - Main container
  • .tab-block-title - Block title
  • .tab-container - Tab layout container (.horizontal or .vertical)
  • .tab-nav - Tab navigation container
  • .tab-nav-item - Individual tab buttons (.active for current tab)
  • .tab-content - Content area
  • .tab-panel - Individual content panels (.hidden for inactive panels)

Screenshots

Backend Settings:

https://share.cleanshot.com/vyGd88Rybns7g2vwmxZW

Backend Settings

Frontend Horizontal View:

https://share.cleanshot.com/3x4DB3JYSZCFyhBR8MK0

Frontend Horizontal View

Frontend Vertical View:

https://share.cleanshot.com/0Q5yBP3KTlszMFMST5Ft

Frontend Vertical View

Development

Testing in Sanity Studio

See Testing a plugin in Sanity Studio for instructions on how to run this plugin with hotreload in your studio.

Examples

Advanced Configuration

// Full customization with all available options
{
  _type: 'tabBlock',
  title: 'Service Information',
  layout: 'vertical',
  titleAlignment: 'center',
  tabTitleAlignment: 'left',
  tabTitleVerticalAlignment: 'start',
  tabContentAlignment: 'left',
  titleColor: {hex: '#2D3748'},
  tabTitleColor: {hex: '#4A5568'},
  tabTitleHoverColor: {hex: '#F7FAFC'},
  activeTabTitleColor: {hex: '#3182CE'},
  tabBackgroundColor: {hex: 'transparent'},
  activeTabBackgroundColor: {hex: '#EBF8FF'},
  tabContentColor: {hex: '#2D3748'},
  tabContentBackgroundColor: {hex: '#F7FAFC'},
  tabs: [
    {
      tabTitle: 'Overview',
      content: [
        {
          _type: 'block',
          children: [{text: 'Comprehensive service overview...'}]
        }
      ]
    },
    {
      tabTitle: 'Features',
      content: [
        {
          _type: 'block',
          children: [{text: 'Key features and benefits...'}]
        }
      ]
    }
  ]
}

Troubleshooting

Common Issues

Issue: Tabs not rendering properly

  • Solution: Ensure you're passing the PortableText component prop

Issue: Styles not applying

  • Solution: Check that color values are in the correct {hex: string} format

Issue: Content not displaying

  • Solution: Verify that tab content is properly structured Portable Text

Performance Tips

  1. Tab Limits: Keep tabs to 10 or fewer for optimal performance and user experience
  2. Content Optimization: Use lazy loading for heavy content in tabs
  3. Mobile Considerations: Consider tab content length and title length for mobile users
  4. Color Usage: Use the built-in color customization rather than custom CSS for better performance
  5. Responsive Testing: Test on various devices to ensure optimal responsive behavior

License

MIT © Multidots