Skip to content

Global Styles panels: fix wrong preset committed and shown when two color presets share a hex - #80497

Merged
ramonjd merged 4 commits into
trunkfrom
fix/duplicate-hex-preset-slug-identity
Jul 22, 2026
Merged

Global Styles panels: fix wrong preset committed and shown when two color presets share a hex#80497
ramonjd merged 4 commits into
trunkfrom
fix/duplicate-hex-preset-slug-identity

Conversation

@ramonjd

@ramonjd ramonjd commented Jul 21, 2026

Copy link
Copy Markdown
Member

What?

Fixes two related bugs in the inspector color controls when a palette contains two presets with the same hex value:

  1. Clicking the preselected swatch to accept an inherited color committed the wrong preset. The decoded hex was re-encoded by palette lookup, which returns the first entry with that hex.
  2. Once any local preset was set, the picker matched selection by hex, so both same-hex swatches rendered as selected.

Follow-up to #77894, raised in #77894 (comment).

How?

  • The accept-inherited interceptor now passes inheritedSlug to setValue, so the encoder keeps the reference the at-rest UI was showing.
  • Each color tab now receives a localSlug extracted from the raw local value. The picker selects by localSlug once a value is set and by inheritedSlug at rest. A slug-less custom value keeps the existing hex fallback.

Testing Instructions

Add to test/emptytheme/theme.json and activate emptytheme:

{
	"settings": {
		"color": {
			"defaultPalette": false,
			"palette": [
				{
					"slug": "dark-background",
					"color": "#000000",
					"name": "Dark background"
				},
				{ "slug": "dark-text", "color": "#000000", "name": "Dark text" }
			]
		}
	},
	"styles": {
		"blocks": {
			"core/paragraph": {
				"color": { "text": "var:preset|color|dark-text" }
			}
		}
	}
}

Accepting the inherited color commits the right preset

  1. New post, add a Paragraph. Confirm in the Code editor it has no textColor or style attribute.
  2. Open Typography > Color. The "Dark text" swatch is checked (hover to confirm the name). Click it.
  3. Check the Code editor: the block must have "textColor":"dark-text". On trunk it gets "dark-background".

Selection follows the stored preset

  1. Reopen the color popover. Only "Dark text" is checked. On trunk both swatches render as selected.
  2. In the Colors panel, set the Link color to "Dark text". Reopen: only "Dark text" is checked.

Custom colors unchanged

  1. Set a custom color of #000000 via the custom picker. Reopen: selection falls back to hex matching, same as trunk.
Kapture.2026-07-21.at.15.20.06.mp4

ramonjd added 2 commits July 21, 2026 12:46
…erited color

Clicking the preselected swatch to accept an inherited color committed
only the decoded value. Re-encoding by hex picks the first palette entry
with that value, so with two presets sharing a hex (e.g. dark-background
and dark-text both #000000) the accepted dark-text was saved as
dark-background.

Pass the inherited slug alongside the value so the encoder short-circuits
to the reference the at-rest UI was showing.
… values

Once a local value was set the picker dropped its slug and fell back to
hex matching, so two presets sharing a hex both rendered as selected and
the first one appeared to be the stored value.

Pass the local value's slug through each color tab and select by it,
mirroring the existing inherited-slug selection at rest. A slug-less
custom value keeps the hex fallback.
@github-actions github-actions Bot added the [Package] Block editor /packages/block-editor label Jul 21, 2026
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Size Change: +31 B (0%)

Total Size: 7.75 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 427 kB +31 B (+0.01%)

compressed-size-action

Copilot AI 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.

Pull request overview

Fixes Global Styles inspector color controls when multiple palette presets share the same hex value, ensuring the correct preset slug is committed and only the intended swatch renders as selected.

Changes:

  • Commit the inherited preset by passing inheritedSlug through the “accept inherited” click path to preserve preset identity.
  • Track selection by slug (localSlug when a local value exists, inheritedSlug at rest) to avoid same-hex presets both appearing selected.
  • Add regression tests covering duplicate-hex palettes for Typography text color and Color panel link color.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/block-editor/src/components/global-styles/typography-panel.js Adds localSlug and ensures inherited selection/commit uses the correct inherited slug.
packages/block-editor/src/components/global-styles/background-panel.js Adds localSlug and fixes picker selection behavior for background color with duplicate-hex presets.
packages/block-editor/src/components/global-styles/color-panel.js Adds localSlug to link/hover and element color tabs so selection follows stored slug instead of hex.
packages/block-editor/src/components/global-styles/color-gradient-dropdown-item.js Centralizes slug-based selection (displayedSlug) and ensures accepting inherited commits with inheritedSlug.
packages/block-editor/src/components/global-styles/test/typography-panel.js Adds regression tests for committing the correct inherited preset and single-swatch selection with duplicate hex values.
packages/block-editor/src/components/global-styles/test/color-panel.js Adds regression test verifying link color selection follows the stored slug with duplicate-hex presets.

@ramonjd ramonjd added the [Type] Bug An existing feature does not function as intended label Jul 21, 2026
?.background,
'color'
),
localSlug: extractPresetSlug(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

A block saves a palette color by its name (slug), not its hex, e.g. dark-text. Like the example in the PR description, two presets can share one hex, so only the slug says which one you picked.

The picker marks the selected circle. It used to match by hex, so same-hex presets both lit up. Now it matches by slug: inheritedSlug when showing the inherited value, localSlug when showing the block's own value.

localSlug is the name read from the block's saved value. Custom colors have no name, so localSlug is empty and the picker falls back to hex matching.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Trunk

Kapture.2026-07-21.at.15.26.16.mp4

This PR

Kapture.2026-07-21.at.15.30.47.mp4

@ramonjd
ramonjd marked this pull request as ready for review July 21, 2026 05:34
@ramonjd
ramonjd requested a review from ellatrix as a code owner July 21, 2026 05:34
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

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: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Co-authored-by: talldan <talldanwp@git.wordpress.org>

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

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@andrewserong andrewserong 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.

Nice work! I've only done the quickest of passes looking at this as I have to skip out for the day. A couple of questions:

  • Re: naming, since we have userValue would it make sense to name this userSlug instead of localSlug to match the inheritedValue / inheritedSlug naming?
  • Do we also need to handle this for gradient presets? (If so, doesn't have to be this PR to fix it, it could be a follow-up)

Matches the existing userValue/inheritedValue naming pair.
@ramonjd

ramonjd commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Re: naming, since we have userValue would it make sense to name this userSlug instead of localSlug to match the inheritedValue / inheritedSlug naming?

Much better. Done!

Do we also need to handle this for gradient presets? (If so, doesn't have to be this PR to fix it, it could be a follow-up)

It's the same bug, but it looks like it needs different handling in a follow up. Fixing it needs GradientPicker to expose the clicked preset's slug and accept a selected slug, which is very likely a change to the component API, so I can plan a follow up and check other supports while I'm at it.

Thanks for testing!

@talldan talldan 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.

Fixes the issue for me, and the code looks pretty reasonable!

Comment thread packages/block-editor/src/components/global-styles/background-panel.js Outdated
@talldan talldan added the Backport to WP 7.1 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Jul 21, 2026
@talldan

talldan commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

I expect it should be in 7.1 so I've added the label ☝️

@andrewserong andrewserong 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 the updates, LGTM and it's still testing well:

2026-07-22.10.05.28.mp4

:shipit:

@ramonjd

ramonjd commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

Thanks a lot for testing, folks! I'll have a look at the gradient follow up

@ramonjd
ramonjd enabled auto-merge (squash) July 22, 2026 01:02
@ramonjd
ramonjd merged commit 90e8e76 into trunk Jul 22, 2026
42 of 46 checks passed
@ramonjd
ramonjd deleted the fix/duplicate-hex-preset-slug-identity branch July 22, 2026 01:35
@github-actions github-actions Bot added this to the Gutenberg 23.7 milestone Jul 22, 2026
@github-actions github-actions Bot removed the Backport to WP 7.1 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Jul 22, 2026
gutenbergplugin pushed a commit that referenced this pull request Jul 22, 2026
…olor presets share a hex (#80497)

Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Co-authored-by: talldan <talldanwp@git.wordpress.org>
@github-actions github-actions Bot added the Backported to WP Core Pull request that has been successfully merged into WP Core label Jul 22, 2026
@github-actions

Copy link
Copy Markdown

I just cherry-picked this PR to the wp/7.1 branch to get it included in the next release: 63bdeed

dd32 pushed a commit to dd32/wordpress-develop that referenced this pull request Jul 22, 2026
This updates the pinned commit hash of the Gutenberg repository from `e73c3c481db0650183f092af157f6e42efe9ee2d` to `4997026b75c922d8a6f77a03d72ed7cad04c7073`.

A full list of changes included in this commit can be found on GitHub: 
WordPress/gutenberg@e73c3c4...4997026

- Notes: Replace blur-deselect bookkeeping with useFocusOutside (WordPress/gutenberg#80222)
- Playlist: Update @SInCE tags to 7.1.0 (WordPress/gutenberg#80317)
- fix playlist block Dimensions Design (WordPress/gutenberg#80312)
- UI: Backport compat overlay fixes to WordPress 7.1 (WordPress/gutenberg#80322)
- Editor: allow selecting which block styles to apply globally (WordPress/gutenberg#79839)
- Global Styles: Reject non-string custom CSS in the REST controller (WordPress/gutenberg#80338)
- Open inspector sidebar when toggling responsive editing (WordPress/gutenberg#80307)
- Client Side Media: Honor image_strip_meta and image_max_bit_depth on the client upload path (WordPress/gutenberg#80218)
- Hide block style variations when state is enabled in global styles (WordPress/gutenberg#80341)
- Media REST API: Fix sideload and finalize for EXIF rotated images (WordPress/gutenberg#80295)
- Fix upload snackbar stuck in uploading state on server-side uploads (WordPress/gutenberg#80345)
- Try fixing responsive layout in Nav block (WordPress/gutenberg#80305)
- Responsive styles: Use viewport dropdown to control states for in-editor global styles sidebar (WordPress/gutenberg#80339)
- RichTextControl: Replace DOM focus tracking with a single React-tree focus boundary (WordPress/gutenberg#80324)
- Notes: Finish WPDS treatment for mention chips (WordPress/gutenberg#80300)
- Notes: Add placeholders to the RichText fields (WordPress/gutenberg#80296)
- Fix upload hang when converting long animated GIFs: decode only the first frame for still outputs (WordPress/gutenberg#80260) (WordPress/gutenberg#80342)
- Device preview dropdown: use active color for device icon when responsive styles are active (WordPress/gutenberg#80346)
- Fix default aspect ratio for lazy loaded Featured image (WordPress/gutenberg#80386)
- Vips/upload-media: consolidate optional params into options objects (WordPress/gutenberg#80330)
- Autocompleters: Don't pre-encode mention search terms (WordPress/gutenberg#80377)
- Animated GIF uploads: generate sub-sizes from the first frame, matching core (WordPress/gutenberg#80268)
- Custom CSS: Fix cascade order against block style variations (WordPress/gutenberg#80340)
- Rich Text: Restore the selection when focus returns to the editable (WordPress/gutenberg#80396)
- Notes: Arm the mention kses allowance on REST note creation (WordPress/gutenberg#80221)
- Fix upload snackbar double-counting a single HEIC upload in Safari (WordPress/gutenberg#80436)
- ContentEditableControl: fix invalid label association with contenteditable div (WordPress/gutenberg#80441)
- Editor: Disable canvas resizing while zoomed out (WordPress/gutenberg#80391)
- Fix Color Picker Cursor Shaking Issue (WordPress/gutenberg#80205) (WordPress/gutenberg#80435)
- Misc fixes for WordPress-Develop 7.0 merges (WordPress/gutenberg#80444)
- Style Book: Restore live global styles updates on the styles route (WordPress/gutenberg#80459)
- Worker threads: reject pending RPC calls on worker failure or termination (WordPress/gutenberg#79955) (WordPress/gutenberg#80421)
- Media: Add timeout and size guardrails to client-side GIF to video conversion (WordPress/gutenberg#80420)
- Post Content: Use the default block appender for empty content (WordPress/gutenberg#80026)
- Block Supports: Handle nested array block gap values properly (WordPress/gutenberg#80464)
- Editor: Restore fixed device preview height for mobile and tablet (WordPress/gutenberg#80466)
- Block Editor: Guard against non-string spacing preset values (WordPress/gutenberg#80467)
- Writing flow: fully select the ancestor when a text selection crosses a nesting boundary (WordPress/gutenberg#80462)
- Block Editor: Reflect inherited Global Styles values in block inspector controls (WordPress/gutenberg#80481)
- Autocomplete: Reference the suggestions list with `aria-controls` and `aria-haspopup` (WordPress/gutenberg#80403) (WordPress/gutenberg#80499)
- Media: Remove the redundant __heicUploadSupport flag (WordPress/gutenberg#80486)
- State control - avoid tertiary variant on toggle to match style of other dropdown toggles (WordPress/gutenberg#80505)
- Icons: Store the sanitized SVG content when registering an icon (WordPress/gutenberg#80508)
- Fix `useHomeEnd` on tabs in mac testing (WordPress/gutenberg#80374)
- Playlist: Fix playback of tracks served without CORS headers (WordPress/gutenberg#80533)
- Redirect editing events to extension handlers under editableRoot (WordPress/gutenberg#80287)
- Writing flow: fully select the items when a selection extends down into a nested item (WordPress/gutenberg#80492)
- Global Styles panels: fix wrong preset committed and shown when two color presets share a hex (WordPress/gutenberg#80497)
- Replaces the `title` attributes used by revision inline diff annotations with `aria-describedby` (WordPress/gutenberg#80440)
- Notes: Remove "Add note" from the inline styles dropdown (WordPress/gutenberg#80531)
- Global Styles: Resolve per-level heading element styles in block inspector controls (WordPress/gutenberg#80495)
- Notes: Render @ mentions as span chips and narrow the kses class allowance (WordPress/gutenberg#80528)
- Revisions: Specify block level diff status via aria-label (WordPress/gutenberg#77779)
- Backport from Core: improve icon name unit tests (WordPress/gutenberg#80552)
- Device type preview: fix collapsing to content height (WordPress/gutenberg#80553)
- Wrap notices in ThemeProvider with 0 corner radius (WordPress/gutenberg#80557)
- Global Styles: Limit the inherited value treatment to the Gutenberg plugin (WordPress/gutenberg#80555)
- Fix crashes when manipulating locked blocks (WordPress/gutenberg#80509)
- Notes: align floating threads with their inline marker (WordPress/gutenberg#79877)

Props wildworks.
See #65529.

git-svn-id: https://develop.svn.wordpress.org/trunk@62824 602fd350-edb4-49c9-b593-d223f7449a82
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Jul 22, 2026
This updates the pinned commit hash of the Gutenberg repository from `e73c3c481db0650183f092af157f6e42efe9ee2d` to `4997026b75c922d8a6f77a03d72ed7cad04c7073`.

A full list of changes included in this commit can be found on GitHub: 
WordPress/gutenberg@e73c3c4...4997026

- Notes: Replace blur-deselect bookkeeping with useFocusOutside (WordPress/gutenberg#80222)
- Playlist: Update @SInCE tags to 7.1.0 (WordPress/gutenberg#80317)
- fix playlist block Dimensions Design (WordPress/gutenberg#80312)
- UI: Backport compat overlay fixes to WordPress 7.1 (WordPress/gutenberg#80322)
- Editor: allow selecting which block styles to apply globally (WordPress/gutenberg#79839)
- Global Styles: Reject non-string custom CSS in the REST controller (WordPress/gutenberg#80338)
- Open inspector sidebar when toggling responsive editing (WordPress/gutenberg#80307)
- Client Side Media: Honor image_strip_meta and image_max_bit_depth on the client upload path (WordPress/gutenberg#80218)
- Hide block style variations when state is enabled in global styles (WordPress/gutenberg#80341)
- Media REST API: Fix sideload and finalize for EXIF rotated images (WordPress/gutenberg#80295)
- Fix upload snackbar stuck in uploading state on server-side uploads (WordPress/gutenberg#80345)
- Try fixing responsive layout in Nav block (WordPress/gutenberg#80305)
- Responsive styles: Use viewport dropdown to control states for in-editor global styles sidebar (WordPress/gutenberg#80339)
- RichTextControl: Replace DOM focus tracking with a single React-tree focus boundary (WordPress/gutenberg#80324)
- Notes: Finish WPDS treatment for mention chips (WordPress/gutenberg#80300)
- Notes: Add placeholders to the RichText fields (WordPress/gutenberg#80296)
- Fix upload hang when converting long animated GIFs: decode only the first frame for still outputs (WordPress/gutenberg#80260) (WordPress/gutenberg#80342)
- Device preview dropdown: use active color for device icon when responsive styles are active (WordPress/gutenberg#80346)
- Fix default aspect ratio for lazy loaded Featured image (WordPress/gutenberg#80386)
- Vips/upload-media: consolidate optional params into options objects (WordPress/gutenberg#80330)
- Autocompleters: Don't pre-encode mention search terms (WordPress/gutenberg#80377)
- Animated GIF uploads: generate sub-sizes from the first frame, matching core (WordPress/gutenberg#80268)
- Custom CSS: Fix cascade order against block style variations (WordPress/gutenberg#80340)
- Rich Text: Restore the selection when focus returns to the editable (WordPress/gutenberg#80396)
- Notes: Arm the mention kses allowance on REST note creation (WordPress/gutenberg#80221)
- Fix upload snackbar double-counting a single HEIC upload in Safari (WordPress/gutenberg#80436)
- ContentEditableControl: fix invalid label association with contenteditable div (WordPress/gutenberg#80441)
- Editor: Disable canvas resizing while zoomed out (WordPress/gutenberg#80391)
- Fix Color Picker Cursor Shaking Issue (WordPress/gutenberg#80205) (WordPress/gutenberg#80435)
- Misc fixes for WordPress-Develop 7.0 merges (WordPress/gutenberg#80444)
- Style Book: Restore live global styles updates on the styles route (WordPress/gutenberg#80459)
- Worker threads: reject pending RPC calls on worker failure or termination (WordPress/gutenberg#79955) (WordPress/gutenberg#80421)
- Media: Add timeout and size guardrails to client-side GIF to video conversion (WordPress/gutenberg#80420)
- Post Content: Use the default block appender for empty content (WordPress/gutenberg#80026)
- Block Supports: Handle nested array block gap values properly (WordPress/gutenberg#80464)
- Editor: Restore fixed device preview height for mobile and tablet (WordPress/gutenberg#80466)
- Block Editor: Guard against non-string spacing preset values (WordPress/gutenberg#80467)
- Writing flow: fully select the ancestor when a text selection crosses a nesting boundary (WordPress/gutenberg#80462)
- Block Editor: Reflect inherited Global Styles values in block inspector controls (WordPress/gutenberg#80481)
- Autocomplete: Reference the suggestions list with `aria-controls` and `aria-haspopup` (WordPress/gutenberg#80403) (WordPress/gutenberg#80499)
- Media: Remove the redundant __heicUploadSupport flag (WordPress/gutenberg#80486)
- State control - avoid tertiary variant on toggle to match style of other dropdown toggles (WordPress/gutenberg#80505)
- Icons: Store the sanitized SVG content when registering an icon (WordPress/gutenberg#80508)
- Fix `useHomeEnd` on tabs in mac testing (WordPress/gutenberg#80374)
- Playlist: Fix playback of tracks served without CORS headers (WordPress/gutenberg#80533)
- Redirect editing events to extension handlers under editableRoot (WordPress/gutenberg#80287)
- Writing flow: fully select the items when a selection extends down into a nested item (WordPress/gutenberg#80492)
- Global Styles panels: fix wrong preset committed and shown when two color presets share a hex (WordPress/gutenberg#80497)
- Replaces the `title` attributes used by revision inline diff annotations with `aria-describedby` (WordPress/gutenberg#80440)
- Notes: Remove "Add note" from the inline styles dropdown (WordPress/gutenberg#80531)
- Global Styles: Resolve per-level heading element styles in block inspector controls (WordPress/gutenberg#80495)
- Notes: Render @ mentions as span chips and narrow the kses class allowance (WordPress/gutenberg#80528)
- Revisions: Specify block level diff status via aria-label (WordPress/gutenberg#77779)
- Backport from Core: improve icon name unit tests (WordPress/gutenberg#80552)
- Device type preview: fix collapsing to content height (WordPress/gutenberg#80553)
- Wrap notices in ThemeProvider with 0 corner radius (WordPress/gutenberg#80557)
- Global Styles: Limit the inherited value treatment to the Gutenberg plugin (WordPress/gutenberg#80555)
- Fix crashes when manipulating locked blocks (WordPress/gutenberg#80509)
- Notes: align floating threads with their inline marker (WordPress/gutenberg#79877)

Props wildworks.
See #65529.
Built from https://develop.svn.wordpress.org/trunk@62824


git-svn-id: http://core.svn.wordpress.org/trunk@62104 1a063a9b-81f0-0310-95a4-ce76da25c4cd
ramonjd added a commit that referenced this pull request Jul 23, 2026
…e a gradient

Same fix as the color presets in #80497, applied to gradients. The
gradient tabs now pass the inherited and user slugs, the picker selects
by slug, encodeGradientValue uses a provided slug instead of matching
the gradient string, and accepting an inherited gradient commits its
slug. Covers the background gradient, legacy color.gradient, and
element gradient controls.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backported to WP Core Pull request that has been successfully merged into WP Core [Package] Block editor /packages/block-editor [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants