Skip to content

Document that Positioned also works inside an Overlay - #190607

Merged
hannah-hyj merged 16 commits into
flutter:masterfrom
fahaddoc:fix/107903-positioned-overlay-docs
Oct 30, 2026
Merged

hannah-hyj merged 16 commits into
flutter:masterfrom
fahaddoc:fix/107903-positioned-overlay-docs

Conversation

@fahaddoc

@fahaddoc fahaddoc commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

Positioned works inside an Overlay as well as a Stack, but its documentation only described the Stack case. This updates the documentation across Positioned, PositionedDirectional, the animated variants and the transition variants.

Fixes #107903.

The path restriction now covers both RenderObjectWidgets and other ParentDataWidgets, including Expanded, and identifies the boundary for each of the three overlay builders. Overlay documents the positioned-child alignment and normal non-positioned-child sizing, with links to canSizeOverlay and alwaysSizeToContent for the cases where a child determines the overlay size.

Documentation only; no behavior or API changes.

Validation from the review rounds is recorded in the inline replies and summary comments. The latest corrections are in a9cecb891.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions Bot added the framework flutter/packages/flutter repository. See also f: labels. label Aug 5, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the documentation for Positioned and PositionedDirectional to clarify that they can be descendants of an Overlay in addition to a Stack. The review feedback suggests refining this documentation to accurately state that the path to the ancestor performing the stack layout (such as Overlay's internal layout widget) must only contain StatelessWidgets or StatefulWidgets, as Overlay itself contains an internal RenderObjectWidget (_Theatre).

@fahaddoc

fahaddoc commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Good catch on the RenderObjectWidget point — OverlayState.build returns _Theater, so the path from a Positioned up to the Overlay widget does cross a RenderObjectWidget, and what I wrote contradicted itself for that case.

I fixed it slightly differently from the suggestion, to avoid describing a private widget in public docs. The Stack paragraph is now back exactly as it was, and the Overlay case is a separate paragraph anchored on OverlayEntry rather than on Overlay:

An [Overlay] lays its entries out using the same stack layout, so the widget built by an [OverlayEntry] can also be a [Positioned], with the same restriction on the path from the [Positioned] widget to the [OverlayEntry].

That statement holds: between the widget an entry builds and the overlay's stack layout there is only _OverlayEntryWidget, TickerMode, an InheritedWidget and a Builder, so a Positioned returned by OverlayEntry.builder reaches it fine. PositionedDirectional got the same treatment.

@Piinks Piinks added the d: api docs Issues with https://api.flutter.dev/ label Aug 11, 2026

@QuncCccccc QuncCccccc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution!

@github-actions github-actions Bot removed the d: api docs Issues with https://api.flutter.dev/ label Aug 12, 2026
@fahaddoc

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Applied both wordings, the subtree phrasing is more accurate anyway since the Positioned doesn't have to be the root of what the entry builds. Also added Overlay to the PositionedDirectional "See also" section, Positioned already had it.

QuncCccccc
QuncCccccc previously approved these changes Aug 12, 2026

@QuncCccccc QuncCccccc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks again for your contribution:)

@QuncCccccc QuncCccccc added the CICD Run CI/CD label Aug 12, 2026
Positioned's doc comment says it must be a descendant of a Stack, but
Overlay lays its entries out with the same stack layout, so a Positioned
inside an OverlayEntry works with no Stack in between. Overlay's own docs
already mention Positioned, so the two read inconsistently today.

PositionedDirectional carries the same sentence and gets the same update.
Saying the path from Positioned to an enclosing Overlay contains only
StatelessWidgets or StatefulWidgets was wrong: OverlayState builds
_Theater, a RenderObjectWidget, so that path always crosses one.

Keep the original Stack paragraph as it was and describe the Overlay case
in terms of the widget built by an OverlayEntry, which is accurate --
between that widget and the overlay's stack layout there is only
_OverlayEntryWidget, TickerMode, an InheritedWidget and a Builder.
Reword the Overlay paragraph on Positioned and PositionedDirectional to talk
about the subtree an OverlayEntry builds rather than the widget it builds, and
add Overlay to the PositionedDirectional 'See also' section.
@QuncCccccc
QuncCccccc force-pushed the fix/107903-positioned-overlay-docs branch from d7ddc40 to 9227cc8 Compare August 12, 2026 20:10
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 12, 2026
@QuncCccccc QuncCccccc added the CICD Run CI/CD label Aug 12, 2026
Positioned and PositionedDirectional still opened by saying they must be a
descendant of a Stack, which contradicts the Overlay paragraph this PR adds.
Describe the requirement in terms of the ancestor that performs the stack
layout instead, and mention OverlayPortal next to OverlayEntry since it is
the declarative API for putting a widget on an Overlay.

AnimatedPositioned, AnimatedPositionedDirectional, PositionedTransition and
RelativePositionedTransition all carried the same "Only works if it's the
child of a Stack" line. Each builds a Positioned directly, with nothing but
Stateless/Stateful widgets in between, so each works on an Overlay too.

The Stack.alignment and non-positioned-child paragraphs stay scoped to Stack,
because _RenderTheater does not behave the same way there: it always aligns
partially positioned children to AlignmentDirectional.topStart and gives
non-positioned children the overlay's size.
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 14, 2026
@github-actions github-actions Bot added the a: animation Animation APIs label Aug 14, 2026
The restriction paragraph listed Overlay as one of the ancestors the path
is measured to, but the path from a Positioned up to the Overlay widget
crosses _Theater, which is a RenderObjectWidget, so the paragraph
contradicted itself for that case. It now names the widget that performs
the stack layout, with Stack as the example, and the Overlay case stays
in its own paragraph anchored on the subtree an OverlayEntry or
OverlayPortal.overlayChildBuilder builds.

Also link Stack and Overlay in the top/right/bottom/left paragraphs, say
"same stack layout algorithm" consistently, and add
CompositedTransformFollower to PositionedDirectional's "See also".
@fahaddoc

Copy link
Copy Markdown
Contributor Author

Pushed. Summary of this round: the restriction paragraph no longer measures the path to the Overlay widget (that was the _Theater contradiction), it measures it to the widget that performs the stack layout, and the Overlay case stays in its own paragraph. Stack and Overlay are linked in the top/right/bottom/left paragraphs, "same stack layout algorithm" is used consistently, and CompositedTransformFollower is now in PositionedDirectional's "See also" as well.

While checking the claims I ran a throwaway test locally rather than trusting the reading: Positioned at the root of an OverlayEntry and deeper in its subtree, in OverlayPortal.overlayChildBuilder and in overlayChildLayoutBuilder, plus PositionedDirectional in RTL, AnimatedPositioned, PositionedTransition and RelativePositionedTransition inside an entry. Also the negative case, a Center between the Positioned and the entry root does throw, and the two Overlay-specific bits the docs now mention, a side-less Positioned landing at topStart (topRight in RTL) and a non-positioned entry getting the overlay size. All of that behaves as documented.

The failing tree-status check is the broken tree, not this PR.

@justinmc
justinmc requested a review from victorsanni September 1, 2026 22:34
@victorsanni
victorsanni self-requested a review September 28, 2026 18:49
@victorsanni victorsanni added the CICD Run CI/CD label Sep 28, 2026

@victorsanni victorsanni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes applied to runtime errors as well? e.g debugTypicalAncestorWidgetClass

Replaces the three-paragraph explanation on Positioned and
PositionedDirectional with the wording from review: name the boundary
up front (the Stack, or the widget OverlayEntry.builder /
OverlayPortal.overlayChildBuilder returns), anchor the stack layout
algorithm to RenderStack, then spell out both boundaries so the Stack
endpoint being a RenderObjectWidget and the Overlay root not being one
are no longer left to inference.

Drops the sentences restating how an Overlay aligns and sizes
non-positioned entries in favour of a pointer to Overlay, so the
Positioned docs do not bitrot if that behaviour changes.

The four short notes on AnimatedPositioned, AnimatedPositionedDirectional,
PositionedTransition and RelativePositionedTransition no longer describe
the widget as the child of an Overlay, which overlay entries are not.
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Oct 10, 2026
@fahaddoc

Copy link
Copy Markdown
Contributor Author

@victorsanni Pushed 6d40313 with this round applied, and replied on each thread inline.

  • Your replacement wording is in Positioned and mirrored in PositionedDirectional, so both boundaries are stated outright rather than inferred.
  • "stack layout algorithm" is anchored to RenderStack.
  • The Overlay align/size sentences are breadcrumbed to Overlay. I applied that to the AlignmentDirectional.topStart sentence just above it as well, since it carries the same bitrot risk — flagged in that thread, happy to put it back.
  • All four short notes now say "Only works inside a [Stack] or an [Overlay]" instead of describing the widget as a child of the overlay.

Before writing the boundary paragraph I checked the three cases against the framework: Positioned as the entry root works, a StatelessWidget that builds one works, and a Center between them throws Incorrect use of ParentDataWidget.

Two things I can't do from my side:

  • I don't have permission to re-request a review — both the REST and GraphQL endpoints refuse for my account — so this won't re-enter your queue on its own. Flagging it here instead, since you asked me to re-request rather than let a PR sit silently.
  • The CICD label came off on the push, so Awaiting CICD label is stuck pending. Could you re-add it?

@QuncCccccc QuncCccccc added the CICD Run CI/CD label Oct 13, 2026

@victorsanni victorsanni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the PR description with the latest state?

The breadcrumbs added last round sent readers to Overlay for how it
aligns and sizes non-positioned entries, but Overlay did not document
that. It now does, next to the Directionality paragraph, and lists
Positioned in its "See also" the way Positioned already lists it.

Also covers the third builder, OverlayPortal.overlayChildLayoutBuilder,
and states the path restriction as "must not contain any
RenderObjectWidgets" instead of listing the two widget kinds that are
allowed. The framework walks up to the first RenderObjectElement, so
anything that is not a RenderObjectWidget is fine, InheritedWidget
included; verified by test before writing it.

The alignment sentence now says an Overlay has no equivalent of
Stack.alignment rather than dropping the subject entirely.
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Oct 16, 2026
@fahaddoc

Copy link
Copy Markdown
Contributor Author

@victorsanni Pushed 7ea27b7 with this round applied, replied on each thread, and rewrote the PR description to the current state as you asked — it still described the original one-file change.

The one that needed real work was your question about whether Overlay actually documents any of this. It did not, so the breadcrumbs from the last round pointed at nothing. Overlay now documents how it lays entries out, right after the Directionality paragraph, and lists Positioned in its "See also". Checked the claims against _RenderTheater first: AlignmentDirectional.topStart.resolve(textDirection), and BoxConstraints.tight(size) for non-positioned children.

The rest:

  • OverlayPortal.overlayChildLayoutBuilder is now named alongside the other two builders.
  • The path rule reads "must not contain any RenderObjectWidgets" instead of listing the allowed kinds, which also answers the InheritedWidget question — the framework walks up to the first RenderObjectElement, so anything that is not a RenderObjectWidget is fine. Verified with a test before rewording.
  • Your alignment wording is in, and both PositionedDirectional spots mirror everything.

Same note as last time: I can't re-request a review from my account — REST returns 404 and GraphQL returns FORBIDDEN: does not have the correct permissions to execute RequestReviews — so this won't re-enter your queue on its own. Flagging it here instead.

@fahaddoc
fahaddoc requested a review from victorsanni October 19, 2026 06:31
Two things the last round got wrong.

The overlay paragraph said a non-positioned entry is given the size of
the overlay and that the overlay never sizes itself to its entries.
_RenderTheater.performLayout only takes constraints.biggest when
!alwaysSizeToContent && constraints.biggest.isFinite; otherwise
_findSizeDeterminingChild picks the topmost non-positioned entry with
canSizeOverlay and the overlay takes that child's size, which the
canSizeOverlay and alwaysSizeToContent docs in the same file already
say. It also said such entries are aligned to AlignmentDirectional
.topStart, but layoutChild gives them tight constraints and
Offset.zero; _resolvedAlignment only reaches
RenderStack.layoutPositionedChild, so it applies to positioned
children that leave an axis unspecified.

The path restriction said it must not contain any RenderObjectWidgets.
That misses ParentDataWidgets: Stack > Expanded > Positioned throws
Incorrect use of ParentDataWidget even though Expanded renders nothing.
Verified with Expanded, Flexible and a nested Positioned.

Also names the three builders consistently instead of saying "Both"
after listing three, covers OverlayPortal in the overlay paragraph, and
fixes the See also entry, since an OverlayEntry is not a widget and so
cannot itself be wrapped.
@fahaddoc

Copy link
Copy Markdown
Contributor Author

@victorsanni Pushed a9cecb8. You were right on all three substantive ones, and two of them were my errors from the last round rather than wording nits.

The overlay paragraph was wrong twice. performLayout only takes constraints.biggest on the !alwaysSizeToContent && constraints.biggest.isFinite branch — otherwise _findSizeDeterminingChild picks the topmost non-positioned entry with canSizeOverlay and the overlay takes that size, which canSizeOverlay and alwaysSizeToContent already document in the same file. And alignment never applies to non-positioned children at all: layoutChild gives them tight constraints and Offset.zero, and _resolvedAlignment only reaches RenderStack.layoutPositionedChild. I had read _alignmentCache and assumed it applied to every child instead of tracing where it is consumed. Took your combined replacement.

The path restriction missed ParentDataWidgets — Stack > Expanded > Positioned throws even though Expanded renders nothing. Took your replacement and verified Expanded, Flexible and a nested Positioned all throw, while a Builder on the path is fine.

The rest: the "Both" sentence now names Stack and Overlay instead of referring back to three APIs, the overlay paragraph covers OverlayPortal, and the "See also" no longer talks about wrapping an entry.

Re-requesting a review still fails from my account (REST 404, GraphQL FORBIDDEN), so flagging it here as before. The CICD label also came off on this push.

@fahaddoc
fahaddoc requested a review from victorsanni October 21, 2026 04:59

@victorsanni victorsanni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@victorsanni victorsanni added the CICD Run CI/CD label Oct 22, 2026

@hannah-hyj hannah-hyj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hannah-hyj
hannah-hyj added this pull request to the merge queue Oct 30, 2026
Merged via the queue into flutter:master with commit c478de9 Oct 30, 2026
23 of 24 checks passed
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 31, 2026
flutter/flutter@5e805bf...ee8b482

2026-10-31 [email protected] Roll Skia from 9bab765df357 to 607de4b035dc (1 revision) (flutter/flutter#195728)
2026-10-31 [email protected] Roll Skia from 284054bec98a to 9bab765df357 (2 revisions) (flutter/flutter#195726)
2026-10-31 [email protected] Roll Skia from 3a3f56f7ddd4 to 284054bec98a (1 revision) (flutter/flutter#195724)
2026-10-31 [email protected] Roll Skia from 466994d27b1e to 3a3f56f7ddd4 (1 revision) (flutter/flutter#195719)
2026-10-30 [email protected] Fix XcodeProjectInterpreter dependency cycle in flutter_tools (flutter/flutter#195694)
2026-10-30 [email protected] Document that Positioned also works inside an Overlay (flutter/flutter#190607)
2026-10-30 [email protected] Roll Skia from ce0b85b46db6 to 466994d27b1e (3 revisions) (flutter/flutter#195711)
2026-10-30 [email protected] Adds Vulkan sync validation test run (flutter/flutter#195596)
2026-10-30 [email protected] [Android] Let the raster thread use every core of a chip without little cores (flutter/flutter#195071)
2026-10-30 [email protected] Roll Skia from 121d04c01e2d to ce0b85b46db6 (6 revisions) (flutter/flutter#195699)
2026-10-30 [email protected] [web] Anchor platform view slots to top-left to fix RTL document layout (flutter/flutter#194601)
2026-10-30 [email protected] Update golden file testing docs (flutter/flutter#195449)
2026-10-30 [email protected] [tool] Migrate Cache.flutterRoot static state to instance configuration (flutter/flutter#190795)
2026-10-30 [email protected] Apply view metrics overrides below the framework (flutter/flutter#194311)
2026-10-30 [email protected] Roll Skia from c0c46ee9f938 to 121d04c01e2d (9 revisions) (flutter/flutter#195687)
2026-10-30 [email protected] Use uniforms in the Porter Duff blend shader instead of specialization constants (flutter/flutter#195458)
2026-10-30 [email protected] [flutter_tools] Inject dependencies into iOS, macOS, and Windows application packages (flutter/flutter#194047)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
gmackall pushed a commit to gmackall/flutter that referenced this pull request Nov 3, 2026
`Positioned` works inside an `Overlay` as well as a `Stack`, but its
documentation only described the `Stack` case. This updates the
documentation across `Positioned`, `PositionedDirectional`, the animated
variants and the transition variants.

Fixes flutter#107903.

The path restriction now covers both `RenderObjectWidget`s and other
`ParentDataWidget`s, including `Expanded`, and identifies the boundary
for each of the three overlay builders. `Overlay` documents the
positioned-child alignment and normal non-positioned-child sizing, with
links to `canSizeOverlay` and `alwaysSizeToContent` for the cases where
a child determines the overlay size.

Documentation only; no behavior or API changes.

Validation from the review rounds is recorded in the inline replies and
summary comments. The latest corrections are in `a9cecb891`.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt]. This PR is test-exempt because it only edits dartdoc
text, with no behavioral or API changes.
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Victor Sanni <[email protected]>
fahaddoc added a commit to fahaddoc/my-developer-profile that referenced this pull request Nov 5, 2026
flutter/flutter#190607 merged on 2026-10-30, so it leads the list as
contributions[0] and gets its own case study.

Also bring the hard-coded copy in line with five merged PRs: the
/open-source metadata and hero, the SEO paragraph, the JSON-LD
description (it credited every PR to flutter/flutter), the tunnel
tagline (still said three) and the OG subtitle. The resume was missing
#192727 too; it now folds the four Flutter PRs into one entry and the
PDFs are regenerated at one page.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: animation Animation APIs CICD Run CI/CD framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update Positioned documentation to mention that Overlay also uses Positioned

5 participants