close
Skip to content

Add welcome dashboard widget with adaptive layout and content#78461

Merged
retrofox merged 38 commits into
trunkfrom
update/welcome-banner-widget
May 20, 2026
Merged

Add welcome dashboard widget with adaptive layout and content#78461
retrofox merged 38 commits into
trunkfrom
update/welcome-banner-widget

Conversation

@retrofox
Copy link
Copy Markdown
Contributor

@retrofox retrofox commented May 20, 2026

What?

Adds a core/welcome dashboard widget that greets the user and surfaces a few entry points, adapting to both its tile size and the active theme.

  • Size-adaptive layout — feature columns reflow with auto-fit; the banner compacts via container queries on narrow/short tiles; it switches to a side-by-side row on wide-and-short tiles (useResizeObserver); and drops to header-only below 120×120.
  • Theme-adaptive content — reads is_block_theme via getCurrentTheme() from core-data. Block themes get the site editor + styles links; classic themes get the Customizer and a block-theme discovery link.
  • Full-bleed presentation via the declarative presentation hint; the surface owns the chrome.
  • Widget chrome gains vertical overflow so any widget scrolls when its content exceeds the tile.
  • Seeds the widget into the default dashboard layout and ships a per-widget package.json.

Still a basic implementation: the version string is static for now, and a general mechanism for passing server-provided data to widgets is left as a follow-up.

Why?

The dashboard needs a welcoming entry point, and the widget framework needs a concrete example exercising resize, presentation, theme-aware content, and chrome scrolling end to end.

How?

  • widgets/welcome/render.tsx composes a Banner and FeatureHighlight cards inside a size-container Stack root, and reads getCurrentTheme()?.is_block_theme to branch columns 2 and 3.
  • Colors use the interactive-neutral-strong token pair; layout adapts via auto-fit, container queries, and an observer-driven row/tiny switch.
  • widget-chrome.module.cssoverflow-y: auto on the content.
  • default-layout-seed.php — seeds the widget at full width.

Testing

  1. Enable the dashboard widgets experiment and open the dashboard.
  2. Resize the welcome tile: wide + short → row; narrow → single column; below ~120×120 → header only.
  3. Switch between a block theme and a classic theme: columns 2 and 3 change (Customizer + block-theme discovery on classic).
  4. Add a tall widget and confirm it scrolls within the tile.

Follow-ups

  • General channel for server-provided data to widgets (the version string is hardcoded for now).
  • Dismissal action for the banner (surface/chrome concern).

retrofox added 23 commits May 18, 2026 13:12
use interactive-neutral-strong pair for dark surface + light text
import Icon from @wordpress/ui alongside Link/Stack/Text and infer
its accepted prop type from the component itself.
wrap content in a Stack root with container-type: inline-size; let
feature columns reflow via auto-fit minmax(220px, 1fr) and shrink
banner padding + min-block-size below 480px.
return the committed layout instead of the original metadata value
when one is already stored.
append welcome-banner (full width, order 0) alongside hello-world
(order 1) and switch from early-return to conditional appends so
both can coexist in the seed.
switch container-type to size so the banner can shrink (min-block-size
and padding) when the tile is constrained vertically.
let widget content scroll vertically when it exceeds the tile height,
in both regular and full-bleed presentations.
constrain the banner with flex-grow + min/max-height instead of a fixed
min-block-size; tighten the narrow breakpoint to 420px and apply
consistent paddings on the column block in both narrow and short modes.
drop the columns wrapper; banner and features now share a single auto-fit
grid. Banner spans all columns by default and shrinks to span 2 once the
widget is wide enough (1200px) so all tiles sit in one row.
revert the unified grid in favour of a column Stack root with a
separate columns Stack. cap the banner with min/max-height so it
stays balanced as the widget grows.
observe the root with useResizeObserver and switch the Stack direction
to row above 900px, giving the banner 35% of the width and letting the
features grid take the rest.
rename the width/height constants for clarity, drop the stale import
comment, and trigger row layout on either a wide or short widget.
give the banner a minimum inline size and clear the container-query
min-block-size so row mode stays consistent; drop dead commented rules.
move the banner markup and styles into components/banner and pass
isWide down so its row-mode and container-query rules live with it.
trim the orphaned banner selectors from the widget root styles.
let the columns track fill and vertically center its rows so the
features stay balanced beside the banner in row layout.
below 120x120 the observer drops the feature columns and renders only
the banner header + link, compacting its padding to fit the tile.
@retrofox retrofox requested a review from spacedmonkey as a code owner May 20, 2026 08:00
@retrofox retrofox self-assigned this May 20, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: retrofox <retrofox@git.wordpress.org>
Co-authored-by: simison <simison@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@retrofox retrofox added [Type] Experimental Experimental feature or API. [Feature] Dashboard WordPress admin dashboard, widget framework, and layout customization labels May 20, 2026
@retrofox retrofox requested review from simison and removed request for spacedmonkey May 20, 2026 08:07
retrofox and others added 2 commits May 20, 2026 09:30
Co-authored-by: Mikael Korpela <mikael@ihminen.org>
Co-authored-by: Mikael Korpela <mikael@ihminen.org>
Comment thread widgets/welcome-banner/widget.json Outdated
Co-authored-by: Mikael Korpela <mikael@ihminen.org>
Comment thread widgets/welcome-banner/widget.ts Outdated
Co-authored-by: Mikael Korpela <mikael@ihminen.org>
Comment thread lib/experimental/dashboard-widgets/default-layout-seed.php Outdated
Co-authored-by: Mikael Korpela <mikael@ihminen.org>
Comment on lines +21 to +27
const className = [
styles.banner,
isWide && styles.wide,
isTiny && styles.tiny,
]
.filter( Boolean )
.join( ' ' );
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.

Would clearly make sense to use clsx here, but can't because we don't have the package.json for each widget? 🤔

It might make sense to try to add it here as a test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, makes sense to me. Or maybe creating a packages.json for all widget types

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm researching this issue, but I think it deserves a separate PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

direction={ isWide ? 'row' : 'column' }
gap="lg"
>
<Banner isWide={ isWide } isTiny={ isTiny } />
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.

Instead of CSS positioning, let's try how Card.FullBleed would work here now?

It's what I'd expect consumers to try and what we should make work easily (if it doesn't already).

We can't really do this Card rendering Stack trick:

<Card.Content render={ <Stack direction="column" gap="lg" /> }>
<Card.FullBleed>
<div
style={ {
height: 160,
background:
'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
} }
/>
</Card.FullBleed>
<Text>Content below the full-bleed area.</Text>
</Card.Content>

...so applying FullBleed on whole thing and then adding padding back might be another way? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Stepping back, the real thing to guarantee here is design coherence: the padding the widget puts around its inner content should match what the chrome (Card.Content) applies.
Card.FullBleed would get us there, but by coupling the widget render to the surface's chrome system.

To me, the way that keeps the two independent is orthogonal: both sides resolve the same DS token (--wpds-dimension-padding-*) rather than one reaching into the other. The token is the shared coordination point, not a direct dependency.

Today, that coherence is by convention: the widget happens to pick the same token Card.Content does.

The missing piece to make it robust is a shared default, a semantic token that both the Chrome and the widget layout resolve from, so the value stays in sync from a single source instead of being matched by hand.

Copy link
Copy Markdown
Member

@simison simison left a comment

Choose a reason for hiding this comment

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

Looking good! Let's get it in.

I think it would still make sense to add in this PR (and fine in follow-up too) a conditional content based on block theme or not, just like the original widget does as well.

Example here that worked well.

Another thing is the "dismissal" button for the header, which can now be hooked into actually removing the banner from the dashboard.

(example here)

@retrofox retrofox changed the title Add welcome banner widget with size-adaptive layout Add Welcome banner widget May 20, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

Flaky tests detected in 3845d69.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/26177260217
📝 Reported issues:

retrofox added 10 commits May 20, 2026 10:30
returning the committed sub-array short-circuited get_user_metadata
with the wrong shape and dropped the preference scope; return the
original value so WordPress resolves the stored layout intact.
drop a redundant flex rule, a leading blank line, and an explanatory
comment in the welcome-banner widget.
align dir and package name with the core/welcome id, update the seed
instance UUID, and declare react in the per-widget package.json.
read is_block_theme from core-data; classic themes get Customizer and
block-theme-discovery links instead of the site editor and styles.
@retrofox retrofox changed the title Add Welcome banner widget Add welcome dashboard widget with adaptive layout and content May 20, 2026
@retrofox
Copy link
Copy Markdown
Contributor Author

Looking good! Let's get it in.

I think it would still make sense to add in this PR (and fine in follow-up too) a conditional content based on block theme or not, just like the original widget does as well.

Done in the latest push. The content is now theme-aware: it reads is_block_theme via getCurrentTheme() from core-data, so block themes keep the site editor + styles links while classic themes get the Customizer and a block-theme discovery link.

@retrofox
Copy link
Copy Markdown
Contributor Author

Another thing is the "dismissal" button for the header, which can now be hooked into actually removing the banner from the dashboard.

This is a major one, similar to the presentation widget property. We need to define a proper mechanism to maintain the contract between the abstractions without coupling them, while still connecting the pieces so that it works.

Having a dismiss button in the widget content (render) sounds reasonable to me.

Working on it on a follow-up.

@retrofox retrofox merged commit 9cd9fa5 into trunk May 20, 2026
50 of 52 checks passed
@retrofox retrofox deleted the update/welcome-banner-widget branch May 20, 2026 22:16
@github-actions github-actions Bot added this to the Gutenberg 23.3 milestone May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Dashboard WordPress admin dashboard, widget framework, and layout customization [Type] Experimental Experimental feature or API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants