diff --git a/packages/block-editor/src/components/color-palette/test/__snapshots__/control.js.snap b/packages/block-editor/src/components/color-palette/test/__snapshots__/control.js.snap
index 3d082a14a92bff..8f02a338d1de2c 100644
--- a/packages/block-editor/src/components/color-palette/test/__snapshots__/control.js.snap
+++ b/packages/block-editor/src/components/color-palette/test/__snapshots__/control.js.snap
@@ -190,9 +190,12 @@ exports[`ColorPaletteControl matches the snapshot 1`] = `
red
#f00
diff --git a/packages/block-editor/src/components/color-palette/test/control.js b/packages/block-editor/src/components/color-palette/test/control.js
index e1a5529544f791..62dd023266512e 100644
--- a/packages/block-editor/src/components/color-palette/test/control.js
+++ b/packages/block-editor/src/components/color-palette/test/control.js
@@ -1,7 +1,14 @@
/**
* External dependencies
*/
-import { render, waitFor, queryByAttribute } from '@testing-library/react';
+import {
+ render,
+ waitFor,
+ queryByAttribute,
+ fireEvent,
+ screen,
+} from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
/**
* Internal dependencies
@@ -37,4 +44,116 @@ describe( 'ColorPaletteControl', () => {
expect( container ).toMatchSnapshot();
} );
+
+ it( 'allows editing hex value on click', async () => {
+ await renderAndValidate(
+
+ );
+
+ const hexValue = screen.getByRole( 'button', {
+ name: /click to edit hex value/i,
+ } );
+ await userEvent.click( hexValue );
+
+ const input = screen.getByRole( 'textbox', {
+ name: /edit color hex value/i,
+ } );
+ expect( input ).toBeInTheDocument();
+ expect( input ).toHaveValue( '#f00' );
+ } );
+
+ it( 'validates hex input on blur', async () => {
+ const onChange = jest.fn();
+ await renderAndValidate(
+
+ );
+
+ const hexValue = screen.getByRole( 'button', {
+ name: /click to edit hex value/i,
+ } );
+ await userEvent.click( hexValue );
+
+ const input = screen.getByRole( 'textbox', {
+ name: /edit color hex value/i,
+ } );
+ await userEvent.clear( input );
+ await userEvent.type( input, '#ff0000' );
+ fireEvent.blur( input );
+
+ expect( onChange ).toHaveBeenCalledWith( '#ff0000' );
+ } );
+
+ it( 'reverts to previous value on invalid hex', async () => {
+ const onChange = jest.fn();
+ await renderAndValidate(
+
+ );
+
+ const hexValue = screen.getByRole( 'button', {
+ name: /click to edit hex value/i,
+ } );
+ await userEvent.click( hexValue );
+
+ const input = screen.getByRole( 'textbox', {
+ name: /edit color hex value/i,
+ } );
+ await userEvent.clear( input );
+ await userEvent.type( input, 'invalid' );
+ fireEvent.blur( input );
+
+ expect( onChange ).not.toHaveBeenCalled();
+ expect(
+ screen.getByRole( 'button', { name: /click to edit hex value/i } )
+ ).toHaveTextContent( '#f00' );
+ } );
+
+ it( 'handles keyboard interaction', async () => {
+ const onChange = jest.fn();
+ await renderAndValidate(
+
+ );
+
+ const hexValue = screen.getByRole( 'button', {
+ name: /click to edit hex value/i,
+ } );
+
+ fireEvent.keyDown( hexValue, { key: 'Enter' } );
+ const input = screen.getByRole( 'textbox', {
+ name: /edit color hex value/i,
+ } );
+ expect( input ).toBeInTheDocument();
+
+ await userEvent.clear( input );
+ await userEvent.type( input, '#00f' );
+ fireEvent.keyDown( input, { key: 'Escape' } );
+
+ expect( onChange ).not.toHaveBeenCalled();
+ expect(
+ screen.getByRole( 'button', { name: /click to edit hex value/i } )
+ ).toHaveTextContent( '#f00' );
+ } );
} );