BorderBoxControl : Remove orphaned color values when border width is cleared#75431
BorderBoxControl : Remove orphaned color values when border width is cleared#75431dpmehta wants to merge 2 commits intoWordPress:trunkfrom
Conversation
|
👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @dpmehta! In case you missed it, we'd love to have you join us in our Slack community. If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information. |
|
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 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. |
|
Thanks for working on this. The components package will need a changelog entry for this change before the PR can be merged. It'd be great to see some unit tests added too! |
|
Having tested, I think this is actually a fairly complex issue, so it might need some further input. Firstly, I noticed the same issue exists not only for split borders, but also for the unified (single) border control. But also I don't think clearing the color value when there's no width is the right approach to fixing this. Users should be able to set color or width independently. This allows for overriding only the color or the width when those values have been set somewhere else (for example in global styles, theme.json or in an external stylesheet). So the bug here seems to be more that the editor doesn't display the border correctly. I'll ping some other contributors for input (@aaronrobertshaw, @andrewserong, @tellthemachines, @ramonjd). |
|
@talldan Thanks for your valuable input , I'd want to explain why I picked this strategy.
So, if we look at current code for border styling, we can see that when the border width is set to zero, the color value for the border is cleared; this is the expected / actual behavior, which is already defined and can be seen in the reference section below. For that test case is also written which you can find below.gutenberg/packages/components/src/border-control/test/index.js Lines 400 to 417 in 6d3b795 In the preceding reference, you can see that the color value is cleared when the border width value is zero, even you can see above test case for the same also written. so from above we can see its deliberate UX decision. So clearing border width value ( which means its undefined ) and setting the width to zero are similar cases, so I thought the same solution should be used, because if we carefully observe existing behavior when the width value is zero, it clearly indicates that color value without valid border width value is not relevant or useful |
|
@andrewserong Thanks for your input. While considering your case, I attempted to follow what you were saying, which is outlined below.
If I understood correctly, you were concerned about global styling? Just wanted to confirm - this is already handled in the fix.Below you can find Screencast for what i explained above :border-styling.mp4 |
Global styles is just one example, but the styles could come from anywhere. In your video it looks like you're using the same color in global styles as in the individual block instance. Try changing colors at the individual block level and you should see the issue (it's what I was trying to show in my screenshot above). I.e. if you set the individual block to red, and then adjust the widths of each side, the red should persist, but in this PR the red would get cleared out. Hope that helps! |
Here's what I'm seeing (similar to what Andrew explains above) given the following scenario:
This PRKapture.2026-02-13.at.10.49.26.mp4TrunkKapture.2026-02-13.at.10.50.32.mp4I think it'd be classed as a regression if users cannot change the color of a border in this scenario. I don't have a solution, but the logic needs to account for inherited widths (e.g., from Global Styles/theme.json). If YES → output both color and inherited width and if NO → don't output anything (no orphaned color). But as Andrew says too "the styles could come from anywhere". |
|
Thanks for raising this @dpmehta and everyone else for the detailed discussion 👍 The underlying bug discussed here, the styling discrepancy between the editor and frontend, is real and definitely worth fixing. However, as others have already flagged, I don't think the approach in this PR is the right one. I've put up a simple fix as an alternative in #75546. Here's a summary of what I found digging into this: The component controls are working as intendedThere's an important distinction between setting width to zero and clearing the width:
These are semantically very different. Stripping the color when width is cleared would silently discard the user's explicit color choice in cases where the width is inherited from elsewhere. Exactly the regression @andrewserong and @ramonjd demonstrated above. The actual cause of the editor/frontend mismatchThe border fallback styles in On the frontend, the PHP style engine outputs individual longhand properties ( In the editor, when all four sides share the same color value, React merges the identical per-side properties into a single When the border is "linked" the styles use shorthand properties but the block also gets the The fixThe alternative PR (#75546) adds a I've added it to SummaryAs this PR would introduce a regression more prominent than the bug being addressed, I propose we close this and proceed with the fix in #75546. |
|
Thanks again for all the work and discussion here 🙏 As we've merged the fix in #75546, I'll close this PR. |

What?
Fixes a mismatch between the editor and frontend when individual border widths are cleared in split border mode. The editor correctly shows only the intended border, but the frontend renders all four borders due to orphaned color values generating unwanted inline CSS.
Fixes #75415
Why?
When a block has a unified border (e.g., 2px solid black on all sides) and the user switches to split border mode and clears the width from individual sides, the color value persists even though the width has been removed.
This results in the saved block attributes containing color-only border sides:
{ "border": { "top": { "width": "2px", "color": "var:preset|color|contrast" }, "right": { "color": "var:preset|color|contrast" }, "bottom": { "color": "var:preset|color|contrast" }, "left": { "color": "var:preset|color|contrast" } } }These orphaned color values are then serialized into inline CSS like
border-right-color,border-bottom-color, andborder-left-color, without correspondingborder-widthdeclarations. Browsers render these with their default width, causing all four borders to appear on the frontend even though only the top border was intended.How?
In
onSplitChange()withinBorderBoxControl'shook.ts, border sides are now sanitized before being passed up to the parent. If a border side has acolorbut nowidth, it is treated as empty (undefined), preventing orphaned color values from being saved to block attributes.A border with only color and no width is not useful and should not be persisted.
Testing Instructions
Expected: Only the top border is visible on the frontend.
Before fix: All four borders appear because orphaned
border-*-colordeclarations are rendered with default browser widths.Screencast or Screenshot
Before fix :
border-issue.mov
After fix :
border-issue-fix.mov