Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/js/_enqueues/lib/admin-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,70 @@
if ( adminBarLogout ) {
adminBarLogout.addEventListener( 'click', emptySessionStorage );
}

// Toggle toolbar visibility with Ctrl+Shift+F keyboard shortcut (frontend only).
if ( ! document.body.classList.contains( 'wp-admin' ) ) {
document.addEventListener( 'keydown', function( event ) {
if ( event.which !== 70 || ! event.ctrlKey || ! event.shiftKey || event.altKey || event.metaKey ) { // Ctrl+Shift+F.
return;
}

event.preventDefault();
toggleToolbar( adminBar );
} );
}
} );

/**
* Toggle the toolbar visibility.
*
* Slides the toolbar out of view and adjusts page spacing by toggling
* the `wp-toolbar-hidden` class on the document element.
*
* @since TBD
*
* @param {HTMLElement} adminBar The admin bar element.
*/
function toggleToolbar( adminBar ) {
var isHidden = document.documentElement.classList.toggle( 'wp-toolbar-hidden' );

adminBar.setAttribute( 'aria-hidden', isHidden ? 'true' : 'false' );
announceToolbarState( isHidden );
}

/**
* Announce toolbar visibility state to screen readers.
*
* @since TBD
*
* @param {boolean} isHidden Whether the toolbar is hidden.
*/
function announceToolbarState( isHidden ) {
var message = isHidden ? window.wpAdminBarL10n.toolbarHidden : window.wpAdminBarL10n.toolbarVisible,
el;

if ( ! message ) {
return;
}

el = document.getElementById( 'wp-toolbar-announce' );

if ( ! el ) {
el = document.createElement( 'div' );
el.id = 'wp-toolbar-announce';
el.className = 'screen-reader-text';
el.setAttribute( 'role', 'status' );
el.setAttribute( 'aria-live', 'polite' );
document.body.appendChild( el );
}

// Clear then set to ensure screen readers re-announce.
el.textContent = '';
setTimeout( function() {
el.textContent = message;
}, 100 );
}

/**
* Remove hover class for top level menu item when escape is pressed.
*
Expand Down
9 changes: 9 additions & 0 deletions src/wp-includes/class-wp-admin-bar.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ public function initialize() {
wp_enqueue_script( 'admin-bar' );
wp_enqueue_style( 'admin-bar' );

wp_localize_script(
'admin-bar',
'wpAdminBarL10n',
array(
'toolbarHidden' => __( 'Toolbar hidden.' ),
'toolbarVisible' => __( 'Toolbar visible.' ),
)
);

/**
* Fires after WP_Admin_Bar is initialized.
*
Expand Down
18 changes: 18 additions & 0 deletions src/wp-includes/css/admin-bar.css
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ html:lang(he-il) .rtl #wpadminbar * {
background: #1d2327;
/* Only visible in Windows High Contrast mode */
outline: 1px solid transparent;
transition: transform 0.2s ease-in-out, visibility 0.2s ease-in-out;
}

/**
* Toolbar toggle hidden state.
*
* Toggled via Ctrl+Shift+F keyboard shortcut on the frontend.
* Sets the admin bar height variable to 0 so all dependent spacing
* (scroll-padding, bump margin) adjusts automatically.
*/
html.wp-toolbar-hidden {
--wp-admin--admin-bar--height: 0px;
margin-top: 0 !important;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why ! important need here?

Copy link
Copy Markdown
Author

@apermo apermo Apr 8, 2026

Choose a reason for hiding this comment

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

The admin bar "bump" styles — which push the page content down to make room for the toolbar — are added as inline CSS via wp_enqueue_admin_bar_bump_styles() in admin-bar.php

function wp_enqueue_admin_bar_bump_styles() {
if ( current_theme_supports( 'admin-bar' ) ) {
$admin_bar_args = get_theme_support( 'admin-bar' );
$header_callback = $admin_bar_args[0]['callback'];
}
if ( empty( $header_callback ) ) {
$header_callback = '_admin_bar_bump_cb';
}
if ( '_admin_bar_bump_cb' !== $header_callback ) {
return;
}
// Back-compat for plugins that disable functionality by unhooking this action.
if ( ! has_action( 'wp_head', $header_callback ) ) {
return;
}
remove_action( 'wp_head', $header_callback );
$css = '
@media screen { html { margin-top: 32px !important; } }
@media screen and ( max-width: 782px ) { html { margin-top: 46px !important; } }
';
wp_add_inline_style( 'admin-bar', $css );
}

That rule uses !important.
Our override:

html.wp-toolbar-hidden { margin-top: 0 !important; }

needs !important too, otherwise the bump style's !important would always win regardless of our higher specificity (html.wp-toolbar-hidden > html). With both using !important, our selector wins because it's more specific — which is exactly what we want.

}

html.wp-toolbar-hidden #wpadminbar {
transform: translateY(-100%);
visibility: hidden;
}

#wpadminbar .ab-sub-wrapper,
Expand Down
Loading