Prop drilling is the name for passing a value down through components that have no use for it. It only needs to reach the bottom, but every component on the path has to accept it, name it, and forward it.
function App() {
const [theme, setTheme] = useState('dark');
return <Layout theme={theme} onToggle={() => setTheme(t => t === 'dark' ? 'light' : 'dark')} />;
}
const Layout = ({ theme, onToggle }) => <Panel theme={theme} onToggle={onToggle} />;
const Panel = ({ theme, onToggle }) => <ThemeButton theme={theme} onToggle={onToggle} />;
function ThemeButton({ theme, onToggle }) { // the only component that cares
return <button className={theme} onClick={onToggle}>Theme: {theme}</button>;
}Layout and Panel are now coupled to a feature they do not implement. Rename theme, add a second value, or move ThemeButton elsewhere, and both change with it. In a real tree the path is longer.

Context is not the first thing to reach for. If a parent merely renders a deep child, pass the child as JSX instead of a prop — <Layout><ThemeButton /></Layout> lets App build the element itself, and Layout never sees theme at all (Containment). If several siblings need the same data, lifting state to their nearest common parent (Lifting State and Keys) is usually enough. Context earns its place when the value is genuinely global to a deep or wide subtree: the theme, the signed-in user, the interface language, or one large feature such as a shopping cart. The price is that every reader needs a matching provider above it in every tree it renders in, tests included.