Skip to main content
TabbedChips (Alpha)
@coinbase/cds-web@8.21.0
A chip component commonly used in filter context to refine a date source
Import
import { TabbedChips } from '@coinbase/cds-web/alpha/tabbed-chips/TabbedChips'
SourceView source codeStorybookView StorybookFigmaView Figma (internal only)
Related components
View as Markdown

Basic usage

Loading...
Live Code
function ExampleDefault() {
  const tabs = [
    { id: 'all', label: 'All' },
    { id: 'swap', label: 'Swap' },
    { id: 'collect', label: 'Collect' },
    { id: 'bridge', label: 'Bridge' },
  ];
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return <TabbedChips activeTab={activeTab} onChange={setActiveTab} tabs={tabs} />;
}

Compact

Loading...
Live Code
function ExampleCompactNoStart() {
  const tabs = [
    { id: 'all', label: 'All' },
    { id: 'swap', label: 'Swap' },
    { id: 'collect', label: 'Collect' },
    { id: 'bridge', label: 'Bridge' },
  ];
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return <TabbedChips activeTab={activeTab} compact onChange={setActiveTab} tabs={tabs} />;
}

Many tabs (paddles)

Paddles & overflow

Paddles appear automatically when the tab list overflows.

Loading...
Live Code
function ExampleWithPaddles() {
  const tabs = Array.from({ length: 12 }).map((_, i) => ({
    id: `tab_${i + 1}`,
    label: `Tab ${i + 1}`,
  }));
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return <TabbedChips activeTab={activeTab} onChange={setActiveTab} tabs={tabs} />;
}

With custom sized paddles

Paddle styling

You can adjust the size of the paddles via styles.paddle.

Loading...
Live Code
function ExampleCustomPaddles() {
  const tabs = Array.from({ length: 10 }).map((_, i) => ({
    id: `t_${i + 1}`,
    label: `Item ${i + 1}`,
  }));
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return (
    <TabbedChips
      activeTab={activeTab}
      onChange={setActiveTab}
      tabs={tabs}
      styles={{ paddle: { transform: 'scale(0.8)' } }}
    />
  );
}

Long text tabs

Loading...
Live Code
function ExampleLongText() {
  const tabs = [
    { id: 'a', label: 'Very long tab label that can wrap on small widths' },
    { id: 'b', label: 'Another extra long label to test overflow' },
    { id: 'c', label: 'Short' },
  ];
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return <TabbedChips activeTab={activeTab} onChange={setActiveTab} tabs={tabs} />;
}

Disabled tab

Loading...
Live Code
function ExampleDisabled() {
  const tabs = [
    { id: 'first', label: 'First' },
    { id: 'second', label: 'Second', disabled: true },
    { id: 'third', label: 'Third' },
  ];
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return <TabbedChips activeTab={activeTab} onChange={setActiveTab} tabs={tabs} />;
}

With start media

Media sizing

For start media, use circular images sized 24×24 for regular chips and 16×16 for compact chips.

Loading...
Live Code
function ExampleWithStart() {
  const icon = { height: 24, width: 24, shape: 'circle', source: assets.eth.imageUrl };
  const compactIcon = { height: 16, width: 16, shape: 'circle', source: assets.eth.imageUrl };
  const tabs = [
    { id: 'all', label: 'All', start: <RemoteImage {...icon} /> },
    { id: 'swap', label: 'Swap', start: <RemoteImage {...icon} /> },
    { id: 'collect', label: 'Collect', start: <RemoteImage {...icon} /> },
    { id: 'bridge', label: 'Bridge', start: <RemoteImage {...icon} /> },
  ];
  const compactTabs = tabs.map((tab) => ({ ...tab, start: <RemoteImage {...compactIcon} /> }));
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return (
    <VStack gap={2}>
      <TabbedChips activeTab={activeTab} onChange={setActiveTab} tabs={tabs} />
      <TabbedChips compact activeTab={activeTab} onChange={setActiveTab} tabs={compactTabs} />
    </VStack>
  );
}

Custom TabComponent

Custom Tab behavior

When providing a custom TabComponent, use useTabsContext() and call updateActiveTab(id) to update selection state. Reflect the active state (e.g., end icon state) based on activeTab?.id === id.

Loading...
Live Code
function CustomTab({ id, label, ...props }: TabbedChipProps) {
  const { activeTab, updateActiveTab } = useTabsContext();
  const isActive = activeTab?.id === id;
  return (
    <MediaChip
      end={<Icon size="s" active={isActive} name="star" />}
      onClick={() => updateActiveTab(id)}
      {...props}
    >
      {label}
    </MediaChip>
  );
}

const tabs = [
  { id: 'all', label: 'All' },
  { id: 'swap', label: 'Swap' },
  { id: 'collect', label: 'Collect' },
];

function Example() {
  const [activeTab, setActiveTab] = useState(tabs[0]);
  return (
    <TabbedChips
      activeTab={activeTab}
      onChange={setActiveTab}
      tabs={tabs}
      TabComponent={CustomTab}
    />
  );
}

render(<Example />);

Is this page useful?

Coinbase Design is an open-source, adaptable system of guidelines, components, and tools that aid the best practices of user interface design for crypto products.