Repository navigation
Premium Analytics: add a per-section header with title and date controls - #50894
Conversation
the subtitle has no source until the date-config formatter lands
scroll moves to the page content so tabs scroll away with it
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
Code Coverage Summary2 files are newly checked for coverage.
|
b781db2 to
8c3c0cb
Compare
chihsuan
left a comment
There was a problem hiding this comment.
Really like the shape of this! 👍
I just noticed a few things while poking at this, and most of them seems because the responsive measurement now that it lives inside the tab panels. I've added a few inline comments.
| value={ section.slug } | ||
| className={ styles.content } | ||
| > | ||
| <div ref={ setContainerElement } className={ styles.sectionHeader }> |
There was a problem hiding this comment.
I wonder if we should make each panel have its own container state?
Right now, all panels share setContainerElement. When switching tabs, the old panel can clear the ref after the new panel sets it, leaving containerElement as null. The filters then measure document.body instead of the actual row. Since the body is much wider, the filters may incorrectly stay in the wide layout.
Screen.Recording.2026-07-30.at.10.49.24.AM.mov
There was a problem hiding this comment.
I wonder if we should make each panel have its own container state?
This is a good question. The composition between SectionHeader and the tabs doesn't look very good. I'll take a look.
There was a problem hiding this comment.
Confirmed, and it happens on every tab switch. Base UI defers the outgoing panel's unmount by a frame, so the incoming panel sets the ref and the old one nulls it right after. The filters then measure document.body, around 208px wider than the real row, which keeps the presets wide between roughly 600 and 810px.
#50906 removes containerElement altogether and has the panel measure its own root, so the shared ref stops existing. The two PRs already conflict in stage.tsx and that is the resolution. What it does not cover is that SectionHeader's controls slot is a shrink-to-fit flex item, so a self-measuring panel would read its own content instead of the row. Tracked in WOOA7S-1837.
| */ | ||
| export function SectionHeader( { title, subtitle, children }: SectionHeaderProps ) { | ||
| return ( | ||
| <Stack direction="row" align="flex-start" justify="space-between"> |
There was a problem hiding this comment.
Yes, 👍 . This will be addressed in a follow-up.
| > | ||
| <div ref={ setContainerElement } className={ styles.sectionHeader }> | ||
| <SectionHeader title={ section.label }> | ||
| <DateFiltersPanel { ...dateFilters } containerElement={ containerElement } /> |
There was a problem hiding this comment.
The container used to mean "how much room do the filters have, but now the title also uses part of this container, so the filters may see 700px even though they only have 500px and incorrectly stay in the wide layout. Should the measured slot have a stable allocated width?
There was a problem hiding this comment.
Same as before. Those controls will change soon, so I'd like to address that in a follow-up. For instance, this PR #50906
| @@ -12,7 +12,7 @@ | |||
| .content { | |||
There was a problem hiding this comment.
I noticed that in mobile view, or on a tall screen, the sticky header may scroll away once we pass the first screen of widgets.
Screen.Recording.2026-07-30.at.10.46.01.AM.mov
There was a problem hiding this comment.
yes, same comment as the previous ones. Let's address it in a follow-up. I don't want to introduce too many changes in this PR
chihsuan
left a comment
There was a problem hiding this comment.
Let's iterate on another PR. 🚢
|
Thanks. We have a few issues that address these tasks. |
covers title heading, subtitle branch, controls slot

Proposed changes
The SectionHeader component
A new
SectionHeaderin the internaluipackage. The left half anchors the section: the title (heading-2xl, rendered as anh2under the breadcrumbh1) plus an optional subtitle.The right half is a slot. The consumer mounts the date controls there, so the component stays purely presentational and owns no date state.
Storybook stories cover the two instances from the design: rolling presets with comparison, and the year surface.
Before

After

Dashboard wiring
Each section panel now renders the header, with the title coming from the section registry's label.
DateFiltersPanelmoves from above the panels into the header's controls slot.Only the active panel mounts, so there is still a single live instance of the filters.
The subtitle is intentionally absent for now. WOOA7S-1824 adds the formatter that derives it from the applied date configuration.
Scroll moves to the page content
The section panel no longer owns a scroll container. The page content scrolls instead, so the section tabs scroll away with it.
This is the groundwork for pinning the header below the page header, tracked in WOOA7S-1825.
A responsive fix on the way
The filters' responsive measurement now targets the full header row instead of a content-sized wrapper.
Before this change, the compact layout could latch on the first shrink and never disengage when space returned.
Related product discussion/links
Linear umbrella: WOOA7S-1793, consistent title and date selection component.
Follow-ups filed: WOOA7S-1824 (dynamic subtitle) and WOOA7S-1825 (sticky header).
Does this pull request change what data or activity we track or use?
No.
Testing instructions
Setup
Build the package with
jetpack build packages/premium-analytics --deps, then open the dashboard atwp-admin/admin.php?page=jetpack-premium-analytics.The header
Each section (Traffic, Insights, Subscribers) renders its title above the widgets, with the date filters aligned to the end of the same row.
The page header keeps the "Analytics" breadcrumb, and the previous page-level subtitle is gone. The section subtitle is absent until WOOA7S-1824 lands.
Scrolling
Scroll the page. The section tabs scroll away with the content, since the page content is the scroll container now.
Screen.Recording.2026-07-29.at.9.30.43.AM.mov
Responsive
Shrink the viewport below ~600px so the presets collapse into the compact select, then widen it again.
The preset pills must return. Before this PR, the compact layout could stay latched.
Storybook
Run
cd projects/js-packages/storybook && pnpm run storybook:devand checkPackages/Premium Analytics/UI/SectionHeader.