What is InheritedWidget?

Medium PriorityAsked in ~55% of Flutter interviews

3 min read

State Management

ConceptWhat it does
Subclass InheritedWidgetHolds the data you want to expose
static of(context)Sugar for context.dependOnInheritedWidgetOfExactType<T>()
updateShouldNotify(old)When you return true, dependent widgets are marked dirty
Dependency registrationCalling of(context) registers the calling element as a dependent — only those rebuild

That last point is the magic: thousands of widgets can sit below your InheritedWidget, but only the ones that called of(context) rebuild when the data changes.


Code in action

class AppTheme extends InheritedWidget {
  const AppTheme({
    super.key,
    required this.colors,
    required super.child,
  });

  final ColorScheme colors;

  static AppTheme of(BuildContext context) {
    final w = context.dependOnInheritedWidgetOfExactType<AppTheme>();
    assert(w != null, 'No AppTheme in tree');
    return w!;
  }

  @override
  bool updateShouldNotify(AppTheme old) => colors != old.colors;
}

// Provide
AppTheme(
  colors: ColorScheme.fromSeed(seedColor: Colors.indigo),
  child: MaterialApp(home: const Home()),
);

// Consume — only widgets that call .of() rebuild on change
class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final colors = AppTheme.of(context).colors;
    return Container(color: colors.primary);
  }
}

Where Flutter already uses it

APIBacking widget
Theme.of(context)_InheritedTheme
MediaQuery.of(context)_MediaQueryFromView
Navigator.of(context)inherited element of _NavigatorScope
Scaffold.of(context)_ScaffoldScope
Provider.of(context) / context.watchInheritedProvider
Riverpod's ProviderScope_ProviderScope (inherited)

So when you ask "should I use InheritedWidget or Provider?" — Provider is just an ergonomic wrapper. Use Provider/Riverpod by default; reach for raw InheritedWidget when you need a tiny dependency without adding a package.


When to write your own vs use a library

SituationChoice
Quick, single-purpose value (theme override, locale)Custom InheritedWidget
Mutable data, change notifications, lifecycleProvider / Riverpod (built on it)
Public package API where users shouldn't add a depCustom InheritedWidget
You're already using a state-management libUse the lib's APIs, not raw inherited widgets

Common mistakes to avoid

// ❌ Reading without registering — won't rebuild on changes
context.getInheritedWidgetOfExactType<AppTheme>();
// ✅ Use dependOnInheritedWidgetOfExactType (.of helpers do this)

// ❌ updateShouldNotify always returning true
@override
bool updateShouldNotify(_) => true;            // unnecessary rebuilds
// ✅ Compare fields properly

// ❌ Storing mutable state directly in an InheritedWidget
// InheritedWidgets are rebuilt on every parent rebuild. Wrap with an
// InheritedNotifier or a StatefulWidget that holds the state.

// ❌ Forgetting that .of(context) returns the NEAREST ancestor
// Two nested AppThemes → the inner one wins for the inner subtree

// ❌ Using context.read inside build for InheritedWidget data
// Subscribe with .of() (or context.watch in Provider) so rebuilds happen.

Interview follow-ups

  1. Why is InheritedWidget faster than passing data via constructors? It's not "faster" — constructor passing is O(1). The win is scope: descendants can read the value without you threading it through every layer, and Flutter only rebuilds the specific widgets that depend on it, not the whole subtree.

  2. What's updateShouldNotify and what happens if you return true unnecessarily? It tells Flutter whether dependents need to rebuild. Returning true when nothing changed forces wasted rebuilds in every descendant that called of(context). Compare meaningfully — preferably with equatable fields or value semantics.

  3. What's the difference between dependOnInheritedWidgetOfExactType and getInheritedWidgetOfExactType? depend… registers the calling element as a dependent — it'll rebuild when the inherited widget changes. get… reads it once without subscribing. Use depend (or .of helpers) for values that can change; get only for one-shot reads (e.g., during initState).

  4. How is Provider built on top of InheritedWidget? Provider wraps an InheritedWidget (actually InheritedProvider) plus a ChangeNotifier/Listenable and exposes context.watch, context.read, context.select helpers. The underlying dispatch mechanism — registering dependents and selectively rebuilding — is exactly the InheritedWidget machinery.


How helpful was this content?

Please sign in to rate this article.