diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php
index 8fbf4b1342..d517916fbe 100644
--- a/src/wp-includes/rest-api.php
+++ b/src/wp-includes/rest-api.php
@@ -966,6 +966,23 @@ function rest_parse_date( $date, $force_utc = false ) {
 	return strtotime( $date );
 }
 
+/**
+ * Parses an 3 or 6 digit hex color (with #).
+ *
+ * @since 5.4.0
+ *
+ * @param string $color 3 or 6 digit hex color (with #).
+ * @return string|boolean
+ */
+function rest_parse_hex_color( $color ) {
+	$regex = '|^#([A-Fa-f0-9]{3}){1,2}$|';
+	if ( ! preg_match( $regex, $color, $matches ) ) {
+		return false;
+	}
+
+	return $color;
+}
+
 /**
  * Parses a date into both its local and UTC equivalent, in MySQL datetime format.
  *
@@ -1314,6 +1331,12 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) {
 
 	if ( isset( $args['format'] ) ) {
 		switch ( $args['format'] ) {
+			case 'hex-color':
+				if ( ! rest_parse_hex_color( $value ) ) {
+					return new WP_Error( 'rest_invalid_color', __( 'Invalid color.' ) );
+				}
+				break;
+
 			case 'date-time':
 				if ( ! rest_parse_date( $value ) ) {
 					return new WP_Error( 'rest_invalid_date', __( 'Invalid date.' ) );
@@ -1470,6 +1493,9 @@ function rest_sanitize_value_from_schema( $value, $args ) {
 
 	if ( isset( $args['format'] ) ) {
 		switch ( $args['format'] ) {
+			case 'hex-color':
+				return sanitize_hex_color( $value );
+
 			case 'date-time':
 				return sanitize_text_field( $value );
 
diff --git a/tests/phpunit/tests/rest-api/rest-controller.php b/tests/phpunit/tests/rest-api/rest-controller.php
index 91e1d0c5b7..5ab9e2b56b 100644
--- a/tests/phpunit/tests/rest-api/rest-controller.php
+++ b/tests/phpunit/tests/rest-api/rest-controller.php
@@ -27,6 +27,10 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
 					'somestring'  => array(
 						'type' => 'string',
 					),
+					'somehex'     => array(
+						'type'   => 'string',
+						'format' => 'hex-color',
+					),
 					'someenum'    => array(
 						'type' => 'string',
 						'enum' => array( 'a' ),
@@ -166,6 +170,21 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
 		);
 	}
 
+	/**
+	 * @ticket 49270
+	 */
+	public function test_validate_schema_format_hex_color() {
+
+		$this->assertTrue(
+			rest_validate_request_arg( '#000000', $this->request, 'somehex' )
+		);
+
+		$this->assertErrorResponse(
+			'rest_invalid_color',
+			rest_validate_request_arg( 'wibble', $this->request, 'somehex' )
+		);
+	}
+
 	public function test_validate_schema_format_date_time() {
 
 		$this->assertTrue(
@@ -218,6 +237,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
 				'someurl',
 				'somedate',
 				'someemail',
+				'somehex',
 				'someenum',
 				'someargoptions',
 				'somedefault',
@@ -247,6 +267,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
 					'someurl',
 					'somedate',
 					'someemail',
+					'somehex',
 					'someenum',
 					'someargoptions',
 					'somedefault',
diff --git a/tests/phpunit/tests/rest-api/rest-schema-validation.php b/tests/phpunit/tests/rest-api/rest-schema-validation.php
index 9c18a846dc..f581510a07 100644
--- a/tests/phpunit/tests/rest-api/rest-schema-validation.php
+++ b/tests/phpunit/tests/rest-api/rest-schema-validation.php
@@ -72,6 +72,19 @@ class WP_Test_REST_Schema_Validation extends WP_UnitTestCase {
 		$this->assertWPError( rest_validate_value_from_schema( 'email', $schema ) );
 	}
 
+	/**
+	 * @ticket 45098
+	 */
+	public function test_format_hex_color() {
+		$schema = array(
+			'type'   => 'string',
+			'format' => 'hex-color',
+		);
+		$this->assertTrue( rest_validate_value_from_schema( '#000000', $schema ) );
+		$this->assertTrue( rest_validate_value_from_schema( '#FFF', $schema ) );
+		$this->assertWPError( rest_validate_value_from_schema( 'WordPress', $schema ) );
+	}
+
 	public function test_format_date_time() {
 		$schema = array(
 			'type'   => 'string',
diff --git a/tests/phpunit/tests/rest-api/rest-test-controller.php b/tests/phpunit/tests/rest-api/rest-test-controller.php
index b79e7cf59b..a06800c3ce 100644
--- a/tests/phpunit/tests/rest-api/rest-test-controller.php
+++ b/tests/phpunit/tests/rest-api/rest-test-controller.php
@@ -64,6 +64,11 @@ class WP_REST_Test_Controller extends WP_REST_Controller {
 					'format'  => 'email',
 					'context' => array( 'view' ),
 				),
+				'somehex'        => array(
+					'type'    => 'string',
+					'format'  => 'hex-color',
+					'context' => array( 'view' ),
+				),
 				'someenum'       => array(
 					'type'    => 'string',
 					'enum'    => array( 'a', 'b', 'c' ),
