Dashboard: per-instance widget settings drawer#78465
Conversation
gear in the widget chrome opens a DataForm drawer; edits stage and commit with the layout, drawer positioned away from the widget
|
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 Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @Copilot. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
@copilot resolve the merge conflicts in this pull request |
# Conflicts: # widgets/hello-world/render.tsx
Resolved and pushed in commit Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
Size Change: 0 B Total Size: 8.04 MB ℹ️ View Unchanged
|
|
Flaky tests detected in fcf9024. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/26209306618
|
|
Neat! The PR description mentions 'gear' but the video shows the A floating button on full-bleed widgets works well, how does this work on regular widgets though? |
Move settings and layout actions onto the shared WidgetToolbar in the grid's actionable-area slot; the chrome header is presentational again.
Updating...
Good question! I'm updating the approach to address properly how to render the toolbar depending on the mode (Normal | Customize) and the widget presentation |
Hidden with opacity so the gear stays tab-reachable; shown on tile hover/focus-within.
…ate/widget-settings # Conflicts: # widgets/hello-world/render.tsx
| return ( | ||
| <IconButton | ||
| icon={ cog } | ||
| label={ getWidgetSettingsTitle( widgetType ) } |
There was a problem hiding this comment.
Just "Settings" or "Widget settings" might work well enough here too, without the widget name.
| // rather than over it. | ||
| const popupStyle = useMemo< React.CSSProperties >( | ||
| () => ( { | ||
| marginTop: '32px', |
There was a problem hiding this comment.
Let's apply this via CSS module and use existing WP Admin CSS tokens and default to 0px; admin bar height differs on desktop (32px) and mobile (48px), and admin bar might not be there at all on some cases (think site editor) when consumers use the future dashboard package.
| widgetType?.example?.attributes ?? | ||
| {} ) as WidgetAttributes; | ||
| const hasForm = !! widget && !! widgetType && fields.length > 0; | ||
|
|
There was a problem hiding this comment.
Would it make sense to just return null when ! hasForm ?
| * Per-tile toolbar shell: anchored top-right (the grid item is the positioned | ||
| * ancestor) with the shared padding and radius. Variants add the background. | ||
| */ | ||
| .widgetToolbar { |
There was a problem hiding this comment.
Thinking it might make sense to reuse the widget actions chrome as a shared component 🤔
Also great if the opacity changes via a quick xs animation (when not in reduced-motion mode), just for added smoothness.
There was a problem hiding this comment.
Oh, I see we have the same component but different styles. 🤔
Let's just share the styles too?
simison
left a comment
There was a problem hiding this comment.
Not super excited about the UI that appears on hover, and left some other minor notes as well, but I think this is still mergeable.
|
It's a delicate balance. If we show permanently then the UI is littered with repetitive icons which can feel overwhelming. Discoverability of the hover pattern seems okay to me, and keeps things clean so that widget content remains the focus. That said, it's a trivial adjustment if we want to course-correct down the road. |
Yes, we can change it in a follow-up. A minor distinction: it isn't only on hover; it also happens on focus. |
Admin-bar height keys off the WP Admin token (32/46px, or absent in the site editor); the drawer returns null when there is no form.

What?
Adds a per-instance settings affordance to the experimental widget dashboard. When a widget type declares an
attributesschema, each instance of it gets a gear control on its tile that opens a side drawer. The drawer renders the type'sattributesstraight throughDataForm, with no per-widget form wiring.The Hello World example widget gains a
messageattribute to demonstrate the flow end to end.Why?
Widget types can already declare a
Field< Item >[]attributes schema and instances already carryattributes, but there was no UI to edit them. This closes the loop: a user can configure a widget instance without touching code.Editing a widget's attributes uses the same
DataForm+ staging/commit flow as the grid "Layout settings" drawer (live preview, Save/Cancel, mutually exclusive with layout editing), so it behaves consistently with the rest of the dashboard.How?
Per-tile actions live in the grid's
actionableAreaslot, a sibling of the widget card that stays interactive while the chrome isinertduring a layout edit. The surface picks one toolbar by mode:WidgetSettingsToolbar(the settings gear) in normal mode.WidgetLayoutToolbar(width menu + remove) while customizing.Both build on a shared
WidgetToolbarshell, so they keep one top-right anchor and one row layout that lines up with the header's title row. The chromeHeaderis now presentational (icon + title) only.A single
WidgetSettingsdrawer is mounted once at the dashboard root. The gear writes the active instance's UUID to the dashboard UI context; the root drawer reacts to it, readswidgetType.attributes, renders<DataForm>, and writes edits to the staging layer (the same buffersetAttributesand the layout toolbar use). Save commits with the layout; any other dismissal reverts. The settings gear is replaced by the layout toolbar while editing, so the shared commit never publishes cross-flow edits.The gear is hidden by default and revealed on tile hover /
:focus-within, kept in the tab order viaopacity(notdisplay) so keyboard and screen-reader users can reach it. It sits in the same top-right anchor for everypresentation(framed, content-bleed, full-bleed), since it no longer depends on the header. Keyboard focus inside a widget's content outlines the tile so Tab users can tell which widget holds focus.The drawer opens from the edge away from the widget so it does not cover it, and offsets past the fixed admin menu when it opens from the inline-start instead of sliding over it.
Testing
gutenberg-dashboard-widgetsexperiment).Screen.Recording.2026-05-22.at.12.02.28.PM.mov
Follow-ups