diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php
index 8fbf4b1342..f485e8ee55 100644
--- a/src/wp-includes/rest-api.php
+++ b/src/wp-includes/rest-api.php
@@ -966,6 +966,25 @@ 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_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 +1333,12 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) {
 
 	if ( isset( $args['format'] ) ) {
 		switch ( $args['format'] ) {
+			case 'color':
+				if ( ! rest_parse_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 +1495,9 @@ function rest_sanitize_value_from_schema( $value, $args ) {
 
 	if ( isset( $args['format'] ) ) {
 		switch ( $args['format'] ) {
+			case 'color':
+				return sanitize_hex_color( $value );
+
 			case 'date-time':
 				return sanitize_text_field( $value );
 
