Skip to content

[material_ui] MaterialUiCompatibilityBridge cannot cover API-signature coupling, only context lookups #191448

Closed
flutter/website
#13821

Description

@cdmunoz

Summary

MaterialUiCompatibilityBridge resolves legacy dependencies that read Material state from the tree (Theme.of, MaterialLocalizations.of). It cannot resolve dependencies that expose an SDK Material type in their public API, because those values cross the boundary as arguments in a call signature rather than as inherited-widget lookups. No widget wrapper can intercept that direction.

This is offered as a documentation/design observation rather than a defect report. The bridge behaves exactly as designed. The issue is that the two coupling modes are indistinguishable to a developer until they compile, which makes migration planning harder than it needs to be.

Steps to reproduce

  1. Depend on a package that returns an SDK Material type from its public API. Minimal real example: flutter_expandable_fab, whose ExpandableFab.location is backed by _ExpandableFabLocation extends StandardFabLocation (SDK).
  2. Migrate the app to material_ui.
  3. Pass that value to a material_ui Scaffold:
Scaffold(
  floatingActionButton: someFab,
  floatingActionButtonLocation: ExpandableFab.location,
)
  1. Wrap in MaterialUiCompatibilityBridge at any level, app-wide via MaterialApp.builder or around the subtree.

Expected results

Some documented path for a legacy package during the coexistence window, or explicit guidance that this case has none.

Actual results

lib/features/journey_detail/journey_detail_page.dart:131:55: Error: The argument type 'FloatingActionButtonLocation/*1*/' can't be assigned to the parameter type 'FloatingActionButtonLocation/*2*/?'.
 - 'FloatingActionButtonLocation/*1*/' is from 'package:flutter/src/material/floating_action_button_location.dart'
 - 'FloatingActionButtonLocation/*2*/' is from 'package:material_ui/src/floating_action_button_location.dart'
          floatingActionButtonLocation: ExpandableFab.location,
                                                      ^

The bridge has no effect on this error, and structurally cannot: it injects Theme and Localizations downward into the subtree, while this value travels upward as a call argument.

Why an adapter does not work either

The natural workaround is to implement the modern type and delegate to the legacy instance. It fails one level deeper:

class BridgedFabLocation extends modern.StandardFabLocation {
  final legacy.FloatingActionButtonLocation legacyLocation = ExpandableFab.location;

  @override
  double getOffsetX(modern.ScaffoldPrelayoutGeometry geometry, double adjustment) {
    return (legacyLocation as legacy.StandardFabLocation).getOffsetX(geometry, adjustment);
  }
}
error • The argument type 'ScaffoldPrelayoutGeometry (… material_ui-1.0.1/lib/src/scaffold.dart)'
can't be assigned to the parameter type 'ScaffoldPrelayoutGeometry (… flutter/lib/src/material/scaffold.dart)'

The override signature is fixed by material_ui and supplies a modern ScaffoldPrelayoutGeometry; the legacy method requires the SDK one. That object is constructed by the Scaffold during its layout pass, so there is no value to convert and no seam to inject a conversion into. Adapting one type relocates the incompatibility inward rather than resolving it.

Context: measured on a production app

Flutter 3.44.7 stable, material_ui 1.0.1, ~18 widget-rendering plugin dependencies. Full migration: 214 import sites across 212 files.

Baseline before migration: 0 errors. After migration: 3 errors (flutter build apk --debug agrees with flutter analyze).

Site Cause Bridge resolves it
MarkdownStyleSheet.fromTheme(Theme.of(context)) ×2 context lookup yes
Scaffold(floatingActionButtonLocation: ExpandableFab.location) API signature no

Wrapping the first two in MaterialUiCompatibilityBridge resolves them. The third is the only remaining error in the entire application.

The takeaway is that the bridge is effective — it reduced ~18 candidate blockers to one. But that one is unconditional: migration stays atomic while any API-signature-coupled package remains in the graph, regardless of bridge coverage.

Related

Suggestion

Two things that would have saved the most time, in rough priority:

  1. State the limit in the MaterialUiCompatibilityBridge dartdoc and the migration guide. Something as short as "the bridge covers packages that read theme/localizations from context; it cannot help packages that expose SDK Material types in their public API" would let teams classify their dependencies before starting.
  2. Consider surfacing it mechanically. The signal is static — does this package expose, return, or subclass an SDK Material type in its public API? If dart fix --code=migrate_design_widgets could warn when it detects such a dependency, teams would learn the true blast radius up front instead of mid-migration. In our case a single check would have shown the entire cutover hinged on one FAB.

Happy to test any revision against this dependency set. If this is already understood and simply out of scope for 1.x, feel free to close.

Activity

  1. Piinks commented on Aug 20, 2026

    @Piinks
    Contributor

    Thanks for the detailed report!!
    In cases like flutter_expandable_fab, that package migrating to material_ui should resolve the issue. The bridge unfortunately can't cover every gap, but glad to hear it covered most cases!

    The doc suggestions are very good here.

  2. added
    p: material_uimaterial_ui package in flutter/packages
    d: api docsIssues with https://api.flutter.dev/
    packageflutter/packages repository. See also p: labels.
    c: proposalA detailed proposal for a change to Flutter
    team-designOwned by Design Languages team
    on Aug 21, 2026
  3. added
    P2Important issues not at the top of the work list
    triaged-designTriaged by Design Languages team
    on Aug 25, 2026
  4. added a commit that references this issue on Aug 28, 2026
  5. added a commit that references this issue on Aug 31, 2026
  6. github-actions commented on Sep 11, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  7. locked as resolved and limited conversation to collaborators on Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: proposalA detailed proposal for a change to Flutterd: api docsIssues with https://api.flutter.dev/p: material_uimaterial_ui package in flutter/packagespackageflutter/packages repository. See also p: labels.team-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions