diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index e5d20bb7b1edd5..d4835f39dec222 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -726,7 +726,7 @@ Help visitors find your content. ([Source](https://github.com/WordPress/gutenber
- **Name:** core/search
- **Category:** widgets
- **Supports:** align (center, left, right), anchor, color (background, gradients, text), typography (fontSize, lineHeight), ~~html~~
-- **Attributes:** buttonPosition, buttonText, buttonUseIcon, label, placeholder, query, showLabel, width, widthUnit
+- **Attributes:** buttonBehavior, buttonPosition, buttonText, buttonUseIcon, isSearchFieldHidden, label, placeholder, query, showLabel, width, widthUnit
## Separator
diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json
index 387295ebb36dea..c3e63556c3ff42 100644
--- a/packages/block-library/src/search/block.json
+++ b/packages/block-library/src/search/block.json
@@ -42,6 +42,14 @@
"query": {
"type": "object",
"default": {}
+ },
+ "buttonBehavior": {
+ "type": "string",
+ "default": "expand-searchfield"
+ },
+ "isSearchFieldHidden": {
+ "type": "boolean",
+ "default": false
}
},
"supports": {
diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js
index 5d82ced145926f..d74e03d216660f 100644
--- a/packages/block-library/src/search/edit.js
+++ b/packages/block-library/src/search/edit.js
@@ -19,7 +19,7 @@ import {
useSetting,
} from '@wordpress/block-editor';
import { useDispatch, useSelect } from '@wordpress/data';
-import { useEffect } from '@wordpress/element';
+import { useEffect, useRef } from '@wordpress/element';
import {
ToolbarDropdownMenu,
ToolbarGroup,
@@ -59,6 +59,8 @@ import {
// button is placed inside wrapper.
const DEFAULT_INNER_PADDING = '4px';
+const BUTTON_BEHAVIOR_EXPAND = 'expand-searchfield';
+
export default function SearchEdit( {
className,
attributes,
@@ -77,6 +79,8 @@ export default function SearchEdit( {
buttonText,
buttonPosition,
buttonUseIcon,
+ buttonBehavior,
+ isSearchFieldHidden,
style,
} = attributes;
@@ -130,12 +134,33 @@ export default function SearchEdit( {
const isButtonPositionOutside = 'button-outside' === buttonPosition;
const hasNoButton = 'no-button' === buttonPosition;
const hasOnlyButton = 'button-only' === buttonPosition;
+ const searchFieldRef = useRef();
+ const buttonRef = useRef();
const units = useCustomUnits( {
availableUnits: [ '%', 'px' ],
defaultValues: { '%': PC_WIDTH_DEFAULT, px: PX_WIDTH_DEFAULT },
} );
+ useEffect( () => {
+ if ( hasOnlyButton && ! isSelected ) {
+ setAttributes( {
+ isSearchFieldHidden: true,
+ } );
+ }
+ }, [ hasOnlyButton, isSelected, setAttributes ] );
+
+ // Show the search field when width changes.
+ useEffect( () => {
+ if ( ! hasOnlyButton || ! isSelected ) {
+ return;
+ }
+
+ setAttributes( {
+ isSearchFieldHidden: false,
+ } );
+ }, [ hasOnlyButton, isSelected, setAttributes, width ] );
+
const getBlockClassNames = () => {
return classnames(
className,
@@ -152,6 +177,12 @@ export default function SearchEdit( {
: undefined,
buttonUseIcon && ! hasNoButton
? 'wp-block-search__icon-button'
+ : undefined,
+ hasOnlyButton && BUTTON_BEHAVIOR_EXPAND === buttonBehavior
+ ? 'wp-block-search__button-behavior-expand'
+ : undefined,
+ hasOnlyButton && isSearchFieldHidden
+ ? 'wp-block-search__searchfield-hidden'
: undefined
);
};
@@ -165,6 +196,7 @@ export default function SearchEdit( {
onClick: () => {
setAttributes( {
buttonPosition: 'button-outside',
+ isSearchFieldHidden: false,
} );
},
},
@@ -176,6 +208,7 @@ export default function SearchEdit( {
onClick: () => {
setAttributes( {
buttonPosition: 'button-inside',
+ isSearchFieldHidden: false,
} );
},
},
@@ -187,6 +220,19 @@ export default function SearchEdit( {
onClick: () => {
setAttributes( {
buttonPosition: 'no-button',
+ isSearchFieldHidden: false,
+ } );
+ },
+ },
+ {
+ role: 'menuitemradio',
+ title: __( 'Button Only' ),
+ isActive: buttonPosition === 'button-only',
+ icon: buttonOnly,
+ onClick: () => {
+ setAttributes( {
+ buttonPosition: 'button-only',
+ isSearchFieldHidden: true,
} );
},
},
@@ -247,6 +293,7 @@ export default function SearchEdit( {
onChange={ ( event ) =>
setAttributes( { placeholder: event.target.value } )
}
+ ref={ searchFieldRef }
/>
);
};
@@ -268,6 +315,13 @@ export default function SearchEdit( {
? { borderRadius }
: borderProps.style ),
};
+ const handleButtonClick = () => {
+ if ( hasOnlyButton && BUTTON_BEHAVIOR_EXPAND === buttonBehavior ) {
+ setAttributes( {
+ isSearchFieldHidden: ! isSearchFieldHidden,
+ } );
+ }
+ };
return (
<>
@@ -281,6 +335,8 @@ export default function SearchEdit( {
? stripHTML( buttonText )
: __( 'Search' )
}
+ onClick={ handleButtonClick }
+ ref={ buttonRef }
>
@@ -297,6 +353,7 @@ export default function SearchEdit( {
onChange={ ( html ) =>
setAttributes( { buttonText: html } )
}
+ onClick={ handleButtonClick }
/>
) }
>
@@ -516,14 +573,15 @@ export default function SearchEdit( {
} }
showHandle={ isSelected }
>
- { ( isButtonPositionInside || isButtonPositionOutside ) && (
+ { ( isButtonPositionInside ||
+ isButtonPositionOutside ||
+ hasOnlyButton ) && (
<>
{ renderTextField() }
{ renderButton() }
>
) }
- { hasOnlyButton && renderButton() }
{ hasNoButton && renderTextField() }
diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php
index f42622551fc562..d125bacd1b51d8 100644
--- a/packages/block-library/src/search/index.php
+++ b/packages/block-library/src/search/index.php
@@ -29,11 +29,14 @@ function render_block_core_search( $attributes ) {
$classnames = classnames_for_block_core_search( $attributes );
$show_label = ( ! empty( $attributes['showLabel'] ) ) ? true : false;
$use_icon_button = ( ! empty( $attributes['buttonUseIcon'] ) ) ? true : false;
- $show_input = ( ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition'] ) ? false : true;
$show_button = ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) ? false : true;
+ $button_position = $show_button ? $attributes['buttonPosition'] : null;
$query_params = ( ! empty( $attributes['query'] ) ) ? $attributes['query'] : array();
+ $button_behavior = ( ! empty( $attributes['buttonBehavior'] ) ) ? $attributes['buttonBehavior'] : 'default';
$input_markup = '';
$button_markup = '';
+ $input_aria = '';
+ $button_aria = '';
$query_params_markup = '';
$inline_styles = styles_for_block_core_search( $attributes );
$color_classes = get_color_classes_for_block_core_search( $attributes );
@@ -64,24 +67,28 @@ function render_block_core_search( $attributes ) {
);
}
- if ( $show_input ) {
- $input_classes = array( 'wp-block-search__input' );
- if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
- $input_classes[] = $border_color_classes;
- }
- if ( ! empty( $typography_classes ) ) {
- $input_classes[] = $typography_classes;
- }
- $input_markup = sprintf(
- '',
- $input_id,
- esc_attr( implode( ' ', $input_classes ) ),
- get_search_query(),
- esc_attr( $attributes['placeholder'] ),
- $inline_styles['input']
- );
+ if ( 'button-only' === $button_position && 'expand-searchfield' === $button_behavior ) {
+ $input_aria = 'aria-hidden="true" tabindex="-1"';
+ wp_enqueue_script( 'wp-block--search-view', plugins_url( 'search/view.min.js', __FILE__ ) );
}
+ $input_classes = array( 'wp-block-search__input' );
+ if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
+ $input_classes[] = $border_color_classes;
+ }
+ if ( ! empty( $typography_classes ) ) {
+ $input_classes[] = $typography_classes;
+ }
+ $input_markup = sprintf(
+ '',
+ $input_id,
+ esc_attr( implode( ' ', $input_classes ) ),
+ get_search_query(),
+ esc_attr( $attributes['placeholder'] ),
+ $inline_styles['input'],
+ $input_aria
+ );
+
if ( count( $query_params ) > 0 ) {
foreach ( $query_params as $param => $value ) {
$query_params_markup .= sprintf(
@@ -101,7 +108,6 @@ function render_block_core_search( $attributes ) {
if ( ! empty( $typography_classes ) ) {
$button_classes[] = $typography_classes;
}
- $aria_label = '';
if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
$button_classes[] = $border_color_classes;
@@ -111,7 +117,7 @@ function render_block_core_search( $attributes ) {
$button_internal_markup = wp_kses_post( $attributes['buttonText'] );
}
} else {
- $aria_label = sprintf( 'aria-label="%s"', esc_attr( wp_strip_all_tags( $attributes['buttonText'] ) ) );
+ $button_aria = sprintf( 'aria-label="%s"', esc_attr( wp_strip_all_tags( $attributes['buttonText'] ) ) );
$button_classes[] = 'has-icon';
$button_internal_markup =
@@ -119,6 +125,9 @@ function render_block_core_search( $attributes ) {
';
}
+ if ( 'expand-searchfield' === $attributes['buttonBehavior'] ) {
+ $button_aria = sprintf( 'aria-label="%s" aria-expanded="false" aria-controls="wp-block-search__input-%s"', __( 'Expand search field' ), esc_attr( $input_id ) );
+ }
// Include the button element class.
$button_classes[] = wp_theme_get_element_class_name( 'button' );
@@ -126,7 +135,7 @@ function render_block_core_search( $attributes ) {
'',
esc_attr( implode( ' ', $button_classes ) ),
$inline_styles['button'],
- $aria_label,
+ $button_aria,
$button_internal_markup
);
}
@@ -188,6 +197,9 @@ function classnames_for_block_core_search( $attributes ) {
if ( 'button-only' === $attributes['buttonPosition'] ) {
$classnames[] = 'wp-block-search__button-only';
+ if ( ! empty( $attributes['buttonBehavior'] ) && 'expand-searchfield' === $attributes['buttonBehavior'] ) {
+ $classnames[] = 'wp-block-search__button-behavior-expand wp-block-search__searchfield-hidden';
+ }
}
}
@@ -294,10 +306,9 @@ function styles_for_block_core_search( $attributes ) {
$show_label = ( isset( $attributes['showLabel'] ) ) && false !== $attributes['showLabel'];
// Add width styles.
- $has_width = ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] );
- $button_only = ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition'];
+ $has_width = ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] );
- if ( $has_width && ! $button_only ) {
+ if ( $has_width ) {
$wrapper_styles[] = sprintf(
'width: %d%s;',
esc_attr( $attributes['width'] ),
diff --git a/packages/block-library/src/search/style.scss b/packages/block-library/src/search/style.scss
index 6f6c550dacbc15..1e813d9cf6f16a 100644
--- a/packages/block-library/src/search/style.scss
+++ b/packages/block-library/src/search/style.scss
@@ -81,3 +81,42 @@ $button-spacing-y: math.div($grid-unit-15, 2); // 6px
.wp-block-search.aligncenter .wp-block-search__inside-wrapper {
margin: auto;
}
+
+.wp-block-search__button-behavior-expand {
+ .wp-block-search__inside-wrapper {
+ transition-property: width;
+ min-width: 0 !important;
+ }
+
+ .wp-block-search__input {
+ transition-duration: 300ms;
+ flex-basis: 100%;
+ }
+
+ // !important here to override inline styles on button only deselected view.
+ &.wp-block-search__searchfield-hidden {
+ overflow: hidden;
+
+ .wp-block-search__inside-wrapper {
+ overflow: hidden;
+ }
+
+ .wp-block-search__input {
+ width: 0 !important;
+ min-width: 0 !important;
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+ border-left-width: 0 !important;
+ border-right-width: 0 !important;
+ flex-grow: 0;
+ margin: 0;
+ flex-basis: 0;
+ }
+ }
+}
+
+.wp-block[data-align="right"] .wp-block-search__button-behavior-expand {
+ .wp-block-search__inside-wrapper {
+ float: right;
+ }
+}
diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js
new file mode 100644
index 00000000000000..6af84de23edcfa
--- /dev/null
+++ b/packages/block-library/src/search/view.js
@@ -0,0 +1,66 @@
+window.addEventListener( 'DOMContentLoaded', () => {
+ const hiddenClass = 'wp-block-search__searchfield-hidden';
+
+ Array.from(
+ document.getElementsByClassName(
+ 'wp-block-search__button-behavior-expand'
+ )
+ ).forEach( ( block ) => {
+ const searchField = block.querySelector( '.wp-block-search__input' );
+ const searchButton = block.querySelector( '.wp-block-search__button' );
+ const searchLabel = block.querySelector( '.wp-block-search__label' );
+ const ariaLabel = searchButton.getAttribute( 'aria-label' );
+ const id = searchField.getAttribute( 'id' );
+
+ const toggleSearchField = ( showSearchField ) => {
+ if ( showSearchField ) {
+ searchField.removeAttribute( 'aria-hidden' );
+ searchField.removeAttribute( 'tabindex' );
+ searchButton.removeAttribute( 'aria-expanded' );
+ searchButton.removeAttribute( 'aria-controls' );
+ searchButton.setAttribute( 'type', 'submit' );
+ searchButton.setAttribute( 'aria-label', 'Submit Search' );
+
+ return block.classList.remove( hiddenClass );
+ }
+
+ searchButton.removeAttribute( 'type' );
+ searchField.setAttribute( 'aria-hidden', 'true' );
+ searchField.setAttribute( 'tabindex', '-1' );
+ searchButton.setAttribute( 'aria-expanded', 'false' );
+ searchButton.setAttribute( 'aria-controls', id );
+ searchButton.setAttribute( 'aria-label', ariaLabel );
+ return block.classList.add( hiddenClass );
+ };
+
+ const hideSearchField = ( e ) => {
+ if ( ! e.target.closest( '.wp-block-search' ) ) {
+ return toggleSearchField( false );
+ }
+
+ if ( e.key === 'Escape' ) {
+ searchButton.focus();
+ return toggleSearchField( false );
+ }
+ };
+
+ const handleButtonClick = ( e ) => {
+ if ( block.classList.contains( hiddenClass ) ) {
+ e.preventDefault();
+ searchField.focus();
+ toggleSearchField( true );
+ }
+ };
+
+ searchButton.removeAttribute( 'type' );
+ searchField.addEventListener( 'keydown', ( e ) => {
+ hideSearchField( e );
+ } );
+ searchButton.addEventListener( 'click', handleButtonClick );
+ searchButton.addEventListener( 'keydown', ( e ) => {
+ hideSearchField( e );
+ } );
+ searchLabel.addEventListener( 'click', handleButtonClick );
+ document.body.addEventListener( 'click', hideSearchField );
+ } );
+} );
diff --git a/test/integration/fixtures/blocks/core__search.json b/test/integration/fixtures/blocks/core__search.json
index 7b6125b5016b37..f692eac10993d8 100644
--- a/test/integration/fixtures/blocks/core__search.json
+++ b/test/integration/fixtures/blocks/core__search.json
@@ -7,7 +7,9 @@
"placeholder": "",
"buttonPosition": "button-outside",
"buttonUseIcon": false,
- "query": {}
+ "query": {},
+ "buttonBehavior": "expand-searchfield",
+ "isSearchFieldHidden": false
},
"innerBlocks": []
}
diff --git a/test/integration/fixtures/blocks/core__search__custom-text.json b/test/integration/fixtures/blocks/core__search__custom-text.json
index 6e874946117966..c763cb60f65e86 100644
--- a/test/integration/fixtures/blocks/core__search__custom-text.json
+++ b/test/integration/fixtures/blocks/core__search__custom-text.json
@@ -9,7 +9,9 @@
"buttonText": "Custom button text",
"buttonPosition": "button-outside",
"buttonUseIcon": false,
- "query": {}
+ "query": {},
+ "buttonBehavior": "expand-searchfield",
+ "isSearchFieldHidden": false
},
"innerBlocks": []
}