mui/material-ui · error · TypeError
No TabContext provided
Error message
No TabContext provided
What it means
TabList from @mui/lab reads shared tab state via useTabContext(); the context returns null (not undefined) when no <TabContext> ancestor is present, and TabList throws a TypeError immediately because it needs context.value to wire aria-controls/ids on its Tab children. It is a hard precondition — TabList cannot render without the context.
Source
Thrown at packages/mui-lab/src/TabList/TabList.js:11
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import Tabs from '@mui/material/Tabs';
import { useTabContext, getTabId, getPanelId } from '../TabContext';
const TabList = React.forwardRef(function TabList(props, ref) {
const { children: childrenProp, ...other } = props;
const context = useTabContext();
if (context === null) {
throw new TypeError('No TabContext provided');
}
const children = React.Children.map(childrenProp, (child) => {
if (!React.isValidElement(child)) {
return null;
}
return React.cloneElement(child, {
// SOMEDAY: `Tabs` will set those themselves
'aria-controls': getPanelId(context, child.props.value),
id: getTabId(context, child.props.value),
});
});
return (
<Tabs {...other} ref={ref} value={context.value}>
{children}
</Tabs>
);View on GitHub (pinned to bdc96df2cb)
Solutions
- Wrap <TabList> (and its sibling <TabPanel>s) in <TabContext value={value}> so useTabContext returns the context object.
- Ensure the same value state is shared by TabContext, TabList, and TabPanel.
- If you do not need the composable API, switch to @mui/material <Tabs> which manages its own state.
Example fix
// before
<TabList onChange={handleChange}>
<Tab label="One" value="1" />
</TabList>
// after
<TabContext value={value}>
<TabList onChange={handleChange}>
<Tab label="One" value="1" />
</TabList>
</TabContext> Defensive patterns
Strategy: validation
Validate before calling
// Ensure a TabContext ancestor exists before mounting TabList.
import { useContext } from 'react';
import { TabContext } from '@mui/lab';
function useHasTabContext() {
return useContext(TabContext) !== null;
} Type guard
import { Context as TabContextReactContext } from '@mui/lab/TabContext'; // pseudo
// In practice, treat presence of <TabContext> in the JSX tree as the guard:
function isInsideTabContext(): boolean { /* use useContext(TabContext) */ return true; } Prevention
- Always render TabList and TabPanel as descendants of <TabContext value={value}>.
- Co-locate TabContext/TabList/TabPanel in the same component file when starting, to avoid accidentally separating them.
- Add an ESLint rule or code review check that flags @mui/lab TabList/TabPanel imports without a TabContext import.
When it happens
Trigger: Rendering <TabList> directly without wrapping it in a <TabContext value={value}>. Common when copy-pasting only the TabList/Tab/TabPanel pieces from a lab tabs example, or when refactoring and accidentally removing the TabContext wrapper.
Common situations: Migrating from @mui/material Tabs to the @mui/lab TabContext/TabList/TabPanel composable API and forgetting the context; conditional rendering that mounts TabList in a branch where TabContext was not rendered.
Related errors
- No TabContext provided
- MUI: MenuListContext is missing. MenuItems must be placed wi
- MUI: RovingTabIndexContext is missing. Roving tab index item
- expected version: string but got '${version}'
- Could not find '${version}' in "${versions}"
AI-assisted analysis of mui/material-ui@bdc96df2cb (2026-08-12).
Data as JSON: /api/errors/112998e1e9ad8d8b.
Report an issue: GitHub.