Block Supports: Relocate text and bg color controls to Typography and Background panels#77279
Block Supports: Relocate text and bg color controls to Typography and Background panels#77279aaronrobertshaw wants to merge 11 commits into
Conversation
|
@jameskoster I took a quick run at what an interim step might look like in terms of relocating the text color control under the Typography panel, and the background color control under the Background panel. Note that the "element" colors like for Link, Heading, Buttons etc. are all still under optional controls on the Color panel at the moment until we work out a drill down approach or similar. An additional step in this exploration could be to add a new Elements panel that behaves as the Color panel does now for the Group block. That is, all the elements are optional controls that can be toggled on and each has a popover containing text, background etc tabs. Not ideal but a reasonable step until we have the ability to drill down and style more than just colors. We'd keep the current Colors panel so that if blocks add ad hoc color controls into that panel they still show as expected. If there's nothing in the Colors panel it wouldn't render at all. Let me know if you think there might be something here we can pursue in the short term. |
|
Size Change: +1.17 kB (+0.02%) Total Size: 7.5 MB 📦 View Changed
|
This would effectively mean the existing Color panel is hidden most of the time, right? If so I think that might be good to include in this PR. Relatedly I'd consider giving the new Elements panel less prominence in the UI, maybe by positioning it at the bottom of the inspector. |
|
Thanks for the direction @jameskoster 👍 I was already working towards both including the elements panel as well as pushing it further down the sidebar. As soon as I have something more functional. I'll demo again. |
|
This is early days and still buggy but here's a quick glimpse of the elements panel approach discussed. The first pass at this was pushed in 9853127 Screen.Recording.2026-04-16.at.5.54.32.pm.mp4 |
|
Neat, that looks pretty good to me. Time to rope in @WordPress/gutenberg-design for some wider feedback. The only quirk I noticed is the placement of the contrast warning. If that appears due to changing the Text color the placement is a bit unexpected. I wonder if we should move that warning to the color popover. That way it'll appear contextually whether you're currently modifying the background or the text color. Additionally it won't clutter the Inspector in situations where users legitimately want low contrast styling. |
|
Thanks for taking another look at this one 🙇
Good idea. I like it 👍 I'll find some time and make it happen on this PR. |
|
Here's a demo of a quick hack at getting the contrast checker warning within the color popovers. I think we might need to put a little thought into how we could present this better to avoid scrollbar within the popover, the popover extending beyond the bottom of the page, or even just the significant layout jump that it causes. Happy to try out any ideas you might have: Screen.Recording.2026-04-18.at.8.00.06.pm.mp4 |
|
Here's a quick mockup of potentially adding a warning icon and tooltip/popover to the color popover when the contrast is too low. We could also display it in color control in the panel as well if we can find a way that it doesn't look too bad beside existing color swatches and the reset button within the control. For now though maybe this will spark further ideas: Screen.Recording.2026-04-19.at.11.46.28.am.mp4 |
|
Nice! Taking this one for a spin, I think it works well. On the badges for low contrast, it's not a poor idea, but given we have color Items that have very long titles, like "Submenu & overlay background" (which already gets elided), I don't think there's room for a badge there. Could we do an unread dot instead? And regardless, because that may be a rabbit hole and a new feature, might be worth keeping separate from this one? That is, can we just keep the yellow notice that exists in trunk already? I see this is already present, I'm thinking the same but with a blue dot instead of a yellow icon: Also, now that we've changed the Color panel, should we move Typography above it?
|
|
Appreciate all the great feedback here 🙇 I'll try and resolve all the new conflicts over the next few days then explore the options in front of us.
I'm not sure how I feel on this one given the two related colors being compared are split across panels. I'll see how it plays if the contrast warning is displayed in both panels, if that's even possible etc. then update again. |
2c7bfcc to
8be2003
Compare
|
I've finished resolving all the conflicts with the recent state based and responsive styling changes. I believe this is back to a functional state. The suggested tweaks have been made and are present in current state of this PR. These include:
It turns out if a block contains a link element and the link element has styles for the block that also has its contrast checked. Having multiple contrast warnings really creates some dramatic layout shift and/or scroll in the block inspector. It'll be even worse if we add another warning to the elements panel when it is considered low contrast and applicable. (Side note, the element color popovers don't have the low contrast dot and tooltip rendered yet but that can be a follow-up if we keep with that approach) Another issue with the current contrast warning being rendered multiple times is that the warning by default is announced by If we were to display a single warning only, at the block level, within the inspector, would that detach the warning too much from the relevant controls? Could the combination of styles and the resulting lack of contrast be a block level concept? The last issue I noticed, which is also present on trunk is that with state-based styles e.g. hover state, the link element there still has a Here's a quick demo of the latest exploring low contrast selections and warning display: Screen.Recording.2026-06-08.at.1.52.24.pm.mp4/cc @jasmussen and @jameskoster any thoughts on the latest changes? It still feels like we need to polish the contrast warning behaviour and UX. |
| ); | ||
|
|
||
| // Announce to screen readers whenever the warning becomes active. | ||
| speak( message ); |
There was a problem hiding this comment.
This would fire on every render that happens while isPoor is true, right? Is there anything else that could trigger a render besides the contrast check?
There was a problem hiding this comment.
Honestly, not sure off the top of my head but the fact that we're rendering 2 contrast warnings (3 if we add one for elements), means we're going to be announcing redundant warnings. Navigating our editor is hard enough I'd say for those relying on screenreaders etc. without introducing this.
There was a problem hiding this comment.
Actually, I was forgetting that I added the speak call here to meet other accessibility warnings I was getting. There might be a different balance or solution here.
There was a problem hiding this comment.
After adding the warning back to the panels. This speak call could be omitted entirely. If it turns out we go back to just the warning in the color popover, I'll gate this in an effect so it only fires on the change from false to true or when color values change.
| const setTextColor = ( newColor ) => { | ||
| onChange( | ||
| setImmutably( | ||
| value, | ||
| [ 'color', 'text' ], | ||
| encodeColorValue( newColor ) | ||
| ) | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Not sure if this is right but I see a regression and I think it might be related to the way trunk passed newSlug.
If I have two custom colors with the same hex value, e.g.,
"color": {
"palette": [
{ "slug": "brand-a", "name": "Brand A", "color": "#e10000" },
{ "slug": "brand-b", "name": "Brand B", "color": "#e10000" }
]
}They're selected, and only brand-a is assignable.
here's how trunk is working
Kapture.2026-06-09.at.14.24.31.mp4
I think it's important coz if the custom color brand-b is ever updated in the theme, it wouldn't have any effect on stored posts with that var.
There was a problem hiding this comment.
Thanks for the quick testing and flagging this.
I'm sure I've messed up the rebase. I'll get a test in place to cover the regression and implement a fix.
There was a problem hiding this comment.
FWIW I've seen two colors showing as "active" before, when the values are the same. Not ideal, but probably also not the fault of this PR.
There was a problem hiding this comment.
I've seen two colors showing as "active" before, when the values are the same. Not ideal, but probably also not the fault of this PR.
I just retested and still see the two colors selected, but the slug does persist after 71ab383 I think. Nice work!
So here I tested by selected the second B and saved, then updated the value in theme.json to check that the change came through.
| observer.observe( blockEl, { | ||
| attributes: true, | ||
| attributeFilter: [ 'class', 'style' ], | ||
| subtree: true, |
There was a problem hiding this comment.
I guess this is unavoidable. In big containers with lots of deeply-nested blocks I'm wondering what the performance trade off would be of calling a lot of getComputedStyle().
There was a problem hiding this comment.
This is mirroring the existing contrast checker that displays the warning in the different panels. So if it has been accepted there I think that is the baseline.
Now, given this means it might be done multiple times with the warning to be displayed in the color popover, it might need optimising if possible or a different approach to ensure performance is maintained or improved.
I'll look into it.
There was a problem hiding this comment.
No biggie if it was there before. Thanks!
|
Nice work, this is trucking along well. Thanks for changing the dot to blue. I will say it's not entirely clear that it's useful after all. It's fine to keep, but it seems like that dot is serving the same purpose that is covered by the contrast notice itself. It may be best to simply remove it after all. Speaking of, the double warnings is the problem to solve to ship this:
Not a solution near term, but I want to connect this to #76996 and #78880 as having potential to be more generic homes for lint, which I consider contrast issues to be. But near term, can we show the contrast warning only inside the panel that has colors set? E.g. the above image is confusing because it is flagging incompatible colors in a panel that does not have colors set. However the following is probably fine, true, and honest:
Not necessarily for this PR, but we could also potentially improve those contrast warnings with clarity, brevity, and specificity. E.g. instead of:
For the typography panel we could do:
For the background panel we could do:
Relatedly, and possibly not the fault of this PR, but I managed to get myself into this state by clicking first one color, then the other:
The duplicate controls called "Color" will take a little getting used to, insofar as one is typography color and the other is background color, with the panel context revealing which is which. I think this is worth shipping as is, feeling out. If that fails, we can always call change the BG color term to "Fill", or "Solid":
|
|
Didn't we add the dot so that we could remove the notice in the Inspector? I think the yellow dot/icon worked a bit better as it conveys meaning. From that perspective I still think it could be displayed as an Info tip in the
|
|
I would agree that it's either the notice, or the dot. Do we have to decide between them in this PR? I'm softly leaning towards the notice, in part out of inertia/cheese-moving, but also because until we have something like #76996, flagging very visibly contrast issues is something that is unique to the block editor compared to other players in the space. |
|
Yes I think it would be fine to tackle separately, especially without a design we're 100% happy with. Ideally it's something we can prioritise though because obviously the double-notice is taking up a lot of valuable space in the Inspector, arguably a regression. Not essential, but an interim solution could be to make the notice(s) dismissible. |
|
The double notice can hopefully be substantially mitigated by worth-doing-anyway changes to when they fire as suggested here, i.e. only show the notice if a color from the panel has actually been set, and rephrase the notice dependant on which panel it shows up on. WDYT? |
|
It can work, but will still produce double-notices in some cases, no? |
|
If there's a color set in both typography and background panels, both of which are poor, there could be two notices, yes. But each would have a bespoke contextual message, and each would still need separate fixing, yes? I.e. if you fix it in one place and that improves the contrast enough for both checks to pass, the notice would disappear in both places, but you'd get to choose where to fix it. I agree, not necessarily perfect, but it's honest, it's truthful, right? |
|
Appreciate all the continued discussion here 🙇 The commits I pushed yesterday implemented all the feedback from #77279 (comment) but it all needed a little further testing before I was going to record a demo.
I flagged earlier the fact that contrast warnings can be triggered by elements too. That means there might be three locations where a color selection could cause low contrast:
Screen.Recording.2026-06-09.at.5.15.57.pm.mp4This PR now has some conflicts with trunk, so I'll sort those out again, then iterate further. I'll link to two separate commits that will demo both the latest notice in panel behaviour and the alternative dot only approach. Hopefully, that will help guide what feels best before we have the linting error solution mentioned earlier. |
39661d4 to
75ed850
Compare
|
Instead of creating a custom ColorPalette component in the block-editor I took a slightly different approach because that would have required too much code duplication or exporting additional inner components. In f30a060, I've created a private variant of the This means:
|
|
There's still a couple of rough edges I need to address in this PR today. I've found that it's possible to get duplicate typography and background panels for template parts. So I'm working on finetuning what is displayed for section blocks vs template parts. Hopefully, if all goes to plan this should be ok for a final review in a few hours. |
Nice. Thanks for finding the middle road here. In the design conversation, it seems like there were good reasons to layout the controls the way they are. My 2c is that it'd have been a shame to discard that effort. |
|
Tested again after the new changes. LGTM so far, and my take is that the private component is the right compromise.
I couldn't reproduce, but sounds like you have a guard in mind for it. |
It was while testing around template parts. I'll add further test instructions after I finish the fix for that. |
|
Flaky tests detected in edc0cb7. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/27815099384
|
To be candid, at this point, I'm happy for that contrast notice to sit in either location. Key here is: it's inside the popover, in context of the color that need changing. Whatever we need to ship this, everything else in this PR feels so strong I'm happy to support it. |
Thanks @jasmussen 👍 I've managed to find a solution that keeps the warning notice where it is in the popover without altering the public API. If we really want to avoid the private component I've created we can and resort at that time to moving the notice to the top or bottom. For now, we can look to merge this and iterate further from there with smaller more targeted tweaks. |
|
With the private variant, this is no longer unsafe to merge, so no hard blockers from my end 👍 But if it doesn't matter much from a design perspective, I don't think it justifies the complexity and maintenance cost in the long run. So to spell it out, the endgame for this private mechanism would be either:
|
Thanks @mirka for the patience and help. Let me just unpack this to be sure I understand completely, because it sounds like there's some nuance that I've missed. Are we talking about this whole color flyout component?
I mistakenly assumed that was several smaller components, one for the major swatch, one for the lists, and so on. If it's one bigger component (guessing ColorPalette), I understand better the concern. What I will say is that all of those are working well, but can also benefit from improvements. I would think that a decision between your proposed options. |
Exactly 👍 I'm saying that if it's ok to position the
|
There really isn't much complexity with f30a060. A type and a thin wrapper for the thin variant along with the simple rendering of the notice within the component. That said, this has been through too many iterations and is blocking some further work on displaying inherited global styles. I'll move this notice to top of the popover and it can be debated further as a follow-up. |
|
I've relocated the contrast warning notice. This now requires adding an extra VStack wrapper to the popover. The PR description and its contrast warning screenshots have been updated accordingly. |
Improve the information architecture of the block inspector and Global Styles sidebars by moving root-level color controls to the panels they belong with: - Text color moves into the Typography panel. - Background color and gradient move into the Background panel, alongside background image. - The Color panel becomes the "Elements" panel, retaining the element-level controls (Links, Headings, Buttons, Captions) via a new `elements` inspector group and `ElementsEdit` hook. Supporting changes: - Extract a shared `ColorGradientDropdownItem` (and a shared `block-editor-color-gradient-item` style class) reused across the Color/Elements, Background, and Typography panels. - Extract a shared `useColorGradientSettings` hook and reuse `extractPresetSlug` / `encodeColorValueWithPalette` for preset encode/decode. - Surface the contrast warning in the panel that owns the failing color, as an always-visible "Low contrast" icon plus an in-popover notice (via a new `ColorPalette` `children` prop), announced once. - Keep background gradients in `style.background.gradient` rather than the legacy color-support `gradient` attribute. - Preserve the text-to-link color sync when relocating text color, and reorder the inspector panels (Typography, Color, Background, …, Elements).
- Add the `ColorPalette` `children` prop to the components CHANGELOG. - Document the contrast checker `messageOverride` prop in its README.
- New unit tests for the Background and Typography panels and the color-value utilities (including preset-slug duplicate-hex coverage and the text-to-link color sync). - New e2e: relocation under per-viewport block style states, and the Elements-panel link color contrast warning. - Update affected unit and e2e tests for the new panel structure, the relocated controls, and the "Elements" panel labels.
… for notice display
…nels for section blocks
2dee875 to
c306392
Compare
|
After the rebase it looks like there are e2e failures related to the latest version of this PR. I'll get them fixed in the next day or so. |
Render the low-contrast notice inside the color popover, directly above the ColorPalette and entirely within the block editor. This drops the private ColorPalette variant in @wordpress/components, so no component API (public or private) is added. Keep ColorPalette as a stable last child and toggle only the notice ahead of it, so the notice appearing or clearing no longer remounts the palette and resets an open custom color picker. A margin on the notice restores the spacing the wrapper used to provide. Simplify the contrast-check wiring shared across the relocated Typography, Background and Elements panels, and trim now-redundant comments. Update the affected e2e specs to scope selectors to the right panel now that more than one color popover can be open, and regenerate the form fixture whose serialized attribute order shifted.
154f804 to
b9d407f
Compare
block-style-variations.spec.js saved block style variations into the shared style-variations theme's global styles and never reset them. This leaked into style-variations.spec.js, where the leftover user config made the Default variation no longer match (areGlobalStylesEqual returned false), failing the first-variation-active assertion once CI shard boundaries co-located the specs. Add a reusable RequestUtils.resetThemeGlobalStyles() helper, have the polluting spec clean up after itself in afterAll, and defensively reset in style-variations.spec.js beforeAll.














What?
See: Block Supports: Add background clip support and combined UI for text gradient selection #76171
Moves the root-level text and background color controls in the block inspector and Global Styles sidebars out of the catch-all Color panel and into the panels they more naturally belong with:
color.text) moves into the Typography panel.color.backgroundand the color-supportcolor.gradient) move into the Background panel, alongside the existing background image andbackground.gradientcontrols.Why?
Right now nearly all the color controls live under a single Color panel, whether you're thinking about typography, background styling, or an element-specific treatment. The one exception is
background.gradient, which alreadysits in the Background panel so it can be composed with a background image — so even today the picture isn't entirely consistent.
Grouping controls by the style aspect they affect should make the sidebars easier to reason about, and put related controls where you're already working: a text color is set from the Typography panel rather than hunted out of a
catch-all, and the gradient controls sit back alongside the rest of the background styling.
This is deliberately an interim step. The element-level controls stay grouped as-is because moving them properly is a much bigger IA question — ideally each element would be a drill-down into its full set of styles (typography,
color, spacing, …) as one cohesive unit. That's out of scope here.
How?
Relocation
color.textpath.elementsinspector group rendered by anElementsEdithook, labelled "Elements".stylesgroup (Typography → Color → Background → … → Border → Elements → Styles).Section blocks
Section blocks (content-only-locked groups, synced patterns, etc.) don't receive these panels through the inspector slots:
BlockStyleControlsreturnsnullwhen a block's editing mode isn'tdefault, so a section'sblock-support fills are gated off — which is why their curated controls have always been direct-rendered rather than slotted. To keep their curation intact, section blocks get a direct-rendered subset of the relocated panels:
These reuse the same hook round-trips as normal blocks (no duplicated logic), via a new optional
asWrapperon the Typography and Background panel hooks. Template parts are excluded and fall through to the full normal panelset, matching their existing behaviour.
Shared UI
ColorGradientDropdownItemcomponent and a shareduseColorGradientSettingshook (plus acolor-valuesutil), reused across the Color, Background, and Typography panelsrather than duplicated three ways.
block-editor-color-gradient-itemclass so the border/layout styles for color dropdown items are defined once. The existing panel-specific classes stay on the DOM for backward compatibility..block-editor-tools-panel-color-gradient-settings__item.first { margin-top: 0 }rule that predated the current first-visible-item handling.Contrast warning
single screen-reader announcement. The shared logic was extracted into a
getContrastWarning()helper and auseBlockColorContrastWarninghook.ContrastCheckercomponent gains amessageOverrideprop so panels can supply more concise copy.ColorGradientControlrenders theNoticeat the top of the color popover — so no changes are made to the@wordpress/componentspackage and nocomponent API (public or private) is added.
Gradient control
style.color.gradient), the one that used to sit in the Color panel. The separatebackground.gradientsupport already lived in the Background panel andisn't relocated here.
background.gradientsupport read and writestyle.background.gradient, falling back tocolor.gradientfor values that haven't migrated yet andclearing
color.gradienton write. Blocks with only color-support gradient keep usingstyle.color.gradient.background-gradientmigration spec keeps passing.Tests & incidental
color.gradient).tools/eslint/suppressions.jsondropped a stale entry; regenerating the file pruned it.Important to note
@wordpress/componentschanges. The contrast notice is rendered by the block editor inside the color control popover; theColorPalettecomponent is untouched and no component API (public or private) is added.falsefor blocks whose only color support is text and/or background. Those blocks no longer get a Color/Elements panel; their controls open in theTypography and Background panels instead.
Color panel for section blocks later if that's preferred.
contributing colors, and each is a place the issue can be fixed.
Testing Instructions
panel. Confirm a template part still shows the full panel set.
Demo
Screen.Recording.2026-06-16.at.8.16.54.pm.mp4