Command Palette

Search for a command to run...

GitHub
ComponentsTabbed View

Tabbed View

A robust, config-driven container component that organizes content into distinct panels. Supports lazy evaluation, state preservation, icons, and disabled states.

React
Radix Tabs

Interactive Demo

Features multiple tabs including icons, a disabled 'Admin Panel' tab, and a lazy-rendered 'Settings' tab.

Attendees
January - June 2024

Installation

Install the TabbedView component.

pnpm dlx shadcn@latest add https://micto-ui-kit.misangono.net/r/micto/tabbed-view.json

Basic Usage

Provide an array of tabs with labels, icons, and content.

import { useState } from "react";
import { TabbedView } from "@/components/micto/tabbed-view";
import { UserIcon, SettingsIcon } from "lucide-react";

export default function BasicTabs() {
  const [activeTab, setActiveTab] = useState("profile");

  return (
    <TabbedView
      tabs={[
        {
          tabValue: "profile",
          label: "Profile",
          icon: UserIcon,
          content: <div>Profile Content Here</div>,
        },
        {
          tabValue: "settings",
          label: "Settings",
          icon: SettingsIcon,
          content: <div>Settings Content Here</div>,
        },
      ]}
      value={activeTab}
      onValueChange={setActiveTab}
    />
  );
}

Lazy Evaluation (Thunk Pattern)

By default, passing a React Element (e.g. <HeavyComponent />) evaluates it immediately. To strictly defer instantiation and execution until the tab is opened, pass a function that returns the component.

import { useState } from "react";
import { TabbedView } from "@/components/micto/tabbed-view";
import { HeavyChartComponent } from "./heavy-chart";

export default function LazyTabs() {
  return (
    <TabbedView
      tabs={[
        {
          tabValue: "fast",
          label: "Fast Tab",
          content: <div>Immediate rendering</div>,
        },
        {
          tabValue: "heavy",
          label: "Heavy Tab",
          // Pass a function to lazy-evaluate the component!
          // HeavyChartComponent won't be instantiated or mounted until this tab is clicked.
          content: () => <HeavyChartComponent />,
        },
      ]}
    />
  );
}

State Preservation (keepMounted)

Radix UI normally unmounts inactive tabs to save memory, which destroys component state (like form inputs). Use keepMounted={true} to hide them via CSS instead, preserving all state.

import { useState } from "react";
import { TabbedView } from "@/components/micto/tabbed-view";

export default function StatefulTabs() {
  return (
    <TabbedView
      // Set to true to keep hidden tabs mounted in the DOM.
      // This preserves state (e.g., input field values) when switching tabs.
      keepMounted={true}
      tabs={[
        {
          tabValue: "form-step-1",
          label: "Step 1",
          content: <input type="text" placeholder="Type here and switch tabs..." />,
        },
        {
          tabValue: "form-step-2",
          label: "Step 2",
          content: <div>Step 2 details</div>,
        },
      ]}
    />
  );
}

TabbedView Props

Root component configuration.

PropTypeDefaultDescription
tabsTabItem[]Array of tab configurations.
defaultValuestringtabs[0].tabValueThe value of the tab that should be active when initially rendered.
valuestringundefinedThe controlled value of the active tab.
onValueChange(value: string) => voidundefinedEvent handler called when the value changes.
keepMountedbooleanfalseIf true, keeps hidden tabs in the DOM so they don't lose state (like form inputs).
classNamestringundefinedOptional CSS classes to apply to the root Tabs component.

TabItem Interface

Configuration object for individual tabs.

PropTypeDefaultDescription
tabValuestringUnique identifier for the tab.
labelReactNodeThe label displayed on the tab trigger.
contentReactNode | (() => ReactNode)The content to display when the tab is active. Pass a function for strict lazy evaluation.
iconElementTypeundefinedOptional icon component (like Lucide icons) to display next to the label.
disabledbooleanfalseIf true, prevents the user from selecting the tab.
classNamestringundefinedOptional CSS classes to apply specifically to this tab's trigger.