-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Masterbar: fix invalid HTML markup #98510
Conversation
Jetpack Cloud live (direct link)
Automattic for Agencies live (direct link)
|
This PR modifies the release build for the following Calypso Apps: For info about this notification, see here: PCYsg-OT6-p2
To test WordPress.com changes, run |
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser: App Entrypoints (~69 bytes removed 📉 [gzipped])
Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used. Async-loaded Components (~70 bytes removed 📉 [gzipped])
React components that are loaded lazily, when a certain part of UI is displayed for the first time. Legend What is parsed and gzip size?Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory. Generated by performance advisor bot at iscalypsofastyet.com. |
6b6d4cc
to
b2eb737
Compare
1096e2a
to
3d58fb3
Compare
componentButtonRef = React.createRef< HTMLButtonElement >(); | ||
componentDivRef = React.createRef< HTMLDivElement >(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By always rendering the wrapper, and either and a
or a button
, componentButtonRef
is not necessary anymore, and componentDivRef
was renamed to wapperRef
for better clarity
const isInComponentButtonRef = this.componentButtonRef.current?.contains( | ||
event.target as Node | ||
); | ||
const isInComponentDivRef = this.componentDivRef.current?.contains( event.target as Node ); | ||
|
||
if ( ! isInComponentButtonRef && ! isInComponentDivRef ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to the comment above, since the wrapper button
was removed, the logic can be simplified to only check whether we're in the wrapper div (which is now always rendered)
@@ -221,49 +216,30 @@ class MasterbarItem extends Component< MasterbarItemProps > { | |||
disabled: this.props.disabled, | |||
}; | |||
|
|||
if ( this.props.url && ! this.props.subItems ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved from
if ( this.props.url && ! this.props.subItems ) {
// render anchor tag
}
if ( this.props.url && this.props.subItems ) {
// render button with anchor tag and sub-menu items as children
}
// else, if props.url is not defined
// render a wrapper div > button > menu items as children (no anchor tag)
to:
- always rendering a wrapper div
- render either a
button
or ana
depending on props.url - render the sub-menu items (when defined) as sibling of the
button
/a
href={ this.props.url } | ||
ref={ this.props.innerRef as LegacyRef< HTMLAnchorElement > } | ||
onTouchEnd={ this.toggleMenuByTouch } | ||
tabIndex={ -1 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we don't render a
/button
nested in a parent button
, the tabindex={-1}
shouldn't be necessary anymore
|
||
return ( | ||
<div className={ this.props.wrapperClassName } ref={ this.componentDivRef }> | ||
<button | ||
<div |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always rendering the div
could cause some styles to break, but I hopefully managed to catch and amend them all. Lots of testing needed to make sure I didn't miss any edge case
E2E test failures could be related, I'll look into them and report. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice simplification, I don't see any major regressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. Monday brain, I just realized that this wasn't changing the sidebar but the masterbar. Testing that, there is a blocking regression on mouse hover here:
Peek.2025-01-20.09-50.mp4
Please dismiss the "needs changes" review once resolved.
- avoid nesting a inside button: render one or the other - always render wrapper div for consistency - render subitems as siblings of the parent menuitem (and not nested) - less forks in the logic - tweak styles to follow the new markup
136c854
to
abd76a2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Reorganize and simplify markup: - avoid nesting a inside button: render one or the other - always render wrapper div for consistency - render subitems as siblings of the parent menuitem (and not nested) - less forks in the logic - tweak styles to follow the new markup * Add back subitems, tweak CSS selectors to match new markup * Remove code comments * Revert to && instead of ternary * Keep submenu opened while hovering
@@ -221,49 +216,30 @@ class MasterbarItem extends Component< MasterbarItemProps > { | |||
disabled: this.props.disabled, | |||
}; | |||
|
|||
if ( this.props.url && ! this.props.subItems ) { | |||
return ( | |||
const MenuItem = ( props: React.HTMLAttributes< HTMLElement > ) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to #98365
Proposed Changes
button
anda
as children ofbutton
Why are these changes being made?
The current structure generates invalid (
button
rendered as a child of anotherbutton
) and generally inaccessible (interactive elements likea
as children ofbutton
) HTML markupNote
This PR only aims at fixing the most critical issue (invalid markup) with the masterbar markup. As documented in #98365, the master bar semantics and general accessibility are still far from ideal — but that should be tackled in separate PRs. Given the effort required for that potential refactor, we should discuss our options carefully before embarking on that endeavour, especially given how we're slowly showing wp-admin screens over calypso ones.
Testing Instructions
/discover
In all of these scenarios:
button
ora
as a child ofbutton
)button
rendered inside abutton
currently displayed ontrunk
should be gonetrunk
Pre-merge Checklist