This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 09350e3d6b2 Add theme config (#58411)
09350e3d6b2 is described below

commit 09350e3d6b2833805cafd872d509cbf34056603d
Author: Zinkue <[email protected]>
AuthorDate: Thu Dec 11 16:50:10 2025 +0100

    Add theme config (#58411)
    
    * Add theme config property
    
    * Add custom theme to Chakra UI's theme
    
    * Add Oklch type and unit tests
    
    * Add UI documentation
    
    * Fix CI test_config
    
    * Fix Oklch regex
    
    * Move ChakraCustomProvider.tsx
    
    * Create defaultSystem
---
 airflow-core/docs/howto/customize-ui.rst           |  89 +++
 .../exmaple_theme_configuration_dark_mode.png      | Bin 0 -> 60070 bytes
 .../exmaple_theme_configuration_light_mode.png     | Bin 0 -> 60098 bytes
 .../src/airflow/api_fastapi/common/types.py        |  71 ++
 .../api_fastapi/core_api/datamodels/ui/config.py   |   3 +-
 .../api_fastapi/core_api/openapi/_private_ui.yaml  |  42 ++
 .../api_fastapi/core_api/routes/ui/config.py       |  23 +
 .../src/airflow/config_templates/config.yml        |  60 ++
 .../airflow/ui/openapi-gen/requests/schemas.gen.ts |  46 +-
 .../airflow/ui/openapi-gen/requests/types.gen.ts   |  18 +
 .../ui/src/context/ChakraCustomProvider.tsx        |  38 ++
 airflow-core/src/airflow/ui/src/main.tsx           |  15 +-
 .../src/pages/TaskInstance/Logs/TaskLogHeader.tsx  |   4 +-
 airflow-core/src/airflow/ui/src/theme.ts           | 724 +++++++++++----------
 .../tests/unit/api_fastapi/common/test_types.py    |  76 +++
 .../api_fastapi/core_api/routes/ui/test_config.py  |  21 +
 docs/spelling_wordlist.txt                         |   1 +
 17 files changed, 861 insertions(+), 370 deletions(-)

diff --git a/airflow-core/docs/howto/customize-ui.rst 
b/airflow-core/docs/howto/customize-ui.rst
index 7d037d2485f..2833f389ca5 100644
--- a/airflow-core/docs/howto/customize-ui.rst
+++ b/airflow-core/docs/howto/customize-ui.rst
@@ -61,6 +61,95 @@ After
 
 .. image:: ../img/change-site-title/example_instance_name_configuration.png
 
+.. _customizing-ui-theme:
+
+Customizing UI theme
+--------------------
+
+We can provide a JSON configuration to customize the UI.
+
+.. important::
+
+  - Currently only the ``brand`` color palette can be customized.
+  - You must supply ``50``-``950`` OKLCH color values for ``brand`` color.
+  - OKLCH colors must have next format ``oklch(l c h)`` For more info see 
:ref:`config:api__theme`
+
+.. note::
+
+  Modifying the ``brand`` color palette you also modify the navbar/sidebar.
+
+To customize the UI, simply:
+
+1.  Add the configuration option of ``theme`` under the ``[api]`` section 
inside ``airflow.cfg``:
+
+.. code-block::
+
+  [api]
+
+  theme = {
+      "tokens": {
+        "colors": {
+          "brand": {
+            "50": { "value": "oklch(0.971 0.013 17.38)" },
+            "100": { "value": "oklch(0.936 0.032 17.717)" },
+            "200": { "value": "oklch(0.885 0.062 18.334)" },
+            "300": { "value": "oklch(0.808 0.114 19.571)" },
+            "400": { "value": "oklch(0.704 0.191 22.216)" },
+            "500": { "value": "oklch(0.637 0.237 25.331)" },
+            "600": { "value": "oklch(0.577 0.245 27.325)" },
+            "700": { "value": "oklch(0.505 0.213 27.518)" },
+            "800": { "value": "oklch(0.444 0.177 26.899)" },
+            "900": { "value": "oklch(0.396 0.141 25.723)" },
+            "950": { "value": "oklch(0.258 0.092 26.042)" }
+          }
+        }
+      }
+    }
+
+
+.. note::
+
+  The whitespace, particularly on the last line, is important so a multi-line 
value works properly. More details can be found in the
+  the `configparser docs 
<https://docs.python.org/3/library/configparser.html#supported-ini-file-structure>`_.
+
+2.  Alternatively, you can set a custom title using the environment variable:
+
+.. code-block::
+
+  AIRFLOW__API__THEME='{
+    "tokens": {
+      "colors": {
+        "brand": {
+          "50": { "value": "oklch(0.971 0.013 17.38)" },
+          "100": { "value": "oklch(0.936 0.032 17.717)" },
+          "200": { "value": "oklch(0.885 0.062 18.334)" },
+          "300": { "value": "oklch(0.808 0.114 19.571)" },
+          "400": { "value": "oklch(0.704 0.191 22.216)" },
+          "500": { "value": "oklch(0.637 0.237 25.331)" },
+          "600": { "value": "oklch(0.577 0.245 27.325)" },
+          "700": { "value": "oklch(0.505 0.213 27.518)" },
+          "800": { "value": "oklch(0.444 0.177 26.899)" },
+          "900": { "value": "oklch(0.396 0.141 25.723)" },
+          "950": { "value": "oklch(0.258 0.092 26.042)" }
+        }
+      }
+    }
+  }'
+
+
+Screenshots
+^^^^^^^^^^^
+
+Light Mode
+""""""""""
+
+.. image:: ../img/change-theme/exmaple_theme_configuration_light_mode.png
+
+Dark Mode
+"""""""""
+
+.. image:: ../img/change-theme/exmaple_theme_configuration_dark_mode.png
+
 |
 
 Adding Dashboard Alert Messages
diff --git 
a/airflow-core/docs/img/change-theme/exmaple_theme_configuration_dark_mode.png 
b/airflow-core/docs/img/change-theme/exmaple_theme_configuration_dark_mode.png
new file mode 100644
index 00000000000..26dc6194b48
Binary files /dev/null and 
b/airflow-core/docs/img/change-theme/exmaple_theme_configuration_dark_mode.png 
differ
diff --git 
a/airflow-core/docs/img/change-theme/exmaple_theme_configuration_light_mode.png 
b/airflow-core/docs/img/change-theme/exmaple_theme_configuration_light_mode.png
new file mode 100644
index 00000000000..95deb9bcf1c
Binary files /dev/null and 
b/airflow-core/docs/img/change-theme/exmaple_theme_configuration_light_mode.png 
differ
diff --git a/airflow-core/src/airflow/api_fastapi/common/types.py 
b/airflow-core/src/airflow/api_fastapi/common/types.py
index c5df6259f4d..a09f1c9b383 100644
--- a/airflow-core/src/airflow/api_fastapi/common/types.py
+++ b/airflow-core/src/airflow/api_fastapi/common/types.py
@@ -16,6 +16,7 @@
 # under the License.
 from __future__ import annotations
 
+import re
 from dataclasses import dataclass
 from datetime import timedelta
 from enum import Enum
@@ -28,6 +29,9 @@ from pydantic import (
     BaseModel,
     BeforeValidator,
     ConfigDict,
+    field_validator,
+    model_serializer,
+    model_validator,
 )
 
 from airflow._shared.timezones import timezone
@@ -107,3 +111,70 @@ class UIAlert(BaseModel):
 
     text: str
     category: Literal["info", "warning", "error"]
+
+
+class OklchColor(BaseModel):
+    """Validates OKLCH color format from string oklch(l c h)."""
+
+    lightness: float
+    chroma: float
+    hue: float
+
+    @model_validator(mode="before")
+    @classmethod
+    def parse_oklch_string(cls, data):
+        if isinstance(data, str):
+            oklch_regex_pattern = r"^oklch\((-?\d+(?:\.\d+)?) 
(-?\d+(?:\.\d+)?) (-?\d+(?:\.\d+)?)\)$"
+            match = re.match(oklch_regex_pattern, data)
+
+            if not match:
+                raise ValueError(f"Invalid OKLCH format: {data} Expected 
format oklch(l c h)")
+
+            ligthness_str, chroma_str, hue_str = match.groups()
+
+            return {
+                "lightness": float(ligthness_str),
+                "chroma": float(chroma_str),
+                "hue": float(hue_str),
+            }
+        return data
+
+    @field_validator("lightness")
+    @classmethod
+    def validate_lightness(cls, value: float) -> float:
+        if value < 0 or value > 1:
+            raise ValueError(f"Invalid lightness: {value} Must be between 0 
and 1")
+        return value
+
+    @field_validator("chroma")
+    @classmethod
+    def validate_chroma(cls, value: float) -> float:
+        if value < 0 or value > 0.5:
+            raise ValueError(f"Invalid chroma: {value} Must be between 0 and 
0.5")
+        return value
+
+    @field_validator("hue")
+    @classmethod
+    def validate_hue(cls, value: float) -> float:
+        if value < 0 or value > 360:
+            raise ValueError(f"Invalid hue: {value} Must be between 0 and 360")
+        return value
+
+    @model_serializer(mode="plain")
+    def serialize_model(self) -> str:
+        return f"oklch({self.lightness} {self.chroma} {self.hue})"
+
+
+class Theme(BaseModel):
+    """JSON to modify Chakra's theme."""
+
+    tokens: dict[
+        Literal["colors"],
+        dict[
+            Literal["brand"],
+            dict[
+                Literal["50", "100", "200", "300", "400", "500", "600", "700", 
"800", "900", "950"],
+                dict[Literal["value"], OklchColor],
+            ],
+        ],
+    ]
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/config.py 
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/config.py
index 5644f49e0cf..59935882e5e 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/config.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/config.py
@@ -18,7 +18,7 @@ from __future__ import annotations
 
 from pydantic import BaseModel
 
-from airflow.api_fastapi.common.types import UIAlert
+from airflow.api_fastapi.common.types import Theme, UIAlert
 
 
 class ConfigResponse(BaseModel):
@@ -35,3 +35,4 @@ class ConfigResponse(BaseModel):
     dashboard_alert: list[UIAlert]
     show_external_log_redirect: bool
     external_log_name: str | None = None
+    theme: Theme
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
index ac7f962d3c1..711c7ba4e16 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
+++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
@@ -1329,6 +1329,8 @@ components:
           - type: string
           - type: 'null'
           title: External Log Name
+        theme:
+          $ref: '#/components/schemas/Theme'
       type: object
       required:
       - page_size
@@ -1341,6 +1343,7 @@ components:
       - test_connection
       - dashboard_alert
       - show_external_log_redirect
+      - theme
       title: ConfigResponse
       description: configuration serializer.
     ConnectionHookFieldBehavior:
@@ -2297,6 +2300,8 @@ components:
       - type
       title: NodeResponse
       description: Node serializer for responses.
+    OklchColor:
+      type: string
     ReprocessBehavior:
       type: string
       enum:
@@ -2650,6 +2655,43 @@ components:
       - name
       title: TeamResponse
       description: Base serializer for Team.
+    Theme:
+      properties:
+        tokens:
+          additionalProperties:
+            additionalProperties:
+              additionalProperties:
+                additionalProperties:
+                  $ref: '#/components/schemas/OklchColor'
+                propertyNames:
+                  const: value
+                type: object
+              propertyNames:
+                enum:
+                - '50'
+                - '100'
+                - '200'
+                - '300'
+                - '400'
+                - '500'
+                - '600'
+                - '700'
+                - '800'
+                - '900'
+                - '950'
+              type: object
+            propertyNames:
+              const: brand
+            type: object
+          propertyNames:
+            const: colors
+          type: object
+          title: Tokens
+      type: object
+      required:
+      - tokens
+      title: Theme
+      description: JSON to modify Chakra's theme.
     TriggerResponse:
       properties:
         id:
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
index c0b7dd2e3b6..98e506af0c1 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/config.py
@@ -16,6 +16,7 @@
 # under the License.
 from __future__ import annotations
 
+from json import loads
 from typing import Any
 
 from fastapi import Depends, status
@@ -31,6 +32,27 @@ from airflow.utils.log.log_reader import TaskLogReader
 
 config_router = AirflowRouter(tags=["Config"])
 
+THEME_FALLBACK = """
+{
+    "tokens": {
+        "colors": {
+            "brand": {
+                "50": { "value": "oklch(0.98 0.006 248.717)" },
+                "100": { "value": "oklch(0.962 0.012 249.46)" },
+                "200": { "value": "oklch(0.923 0.023 255.082)" },
+                "300": { "value": "oklch(0.865 0.039 252.42)" },
+                "400": { "value": "oklch(0.705 0.066 256.378)" },
+                "500": { "value": "oklch(0.575 0.08 257.759)" },
+                "600": { "value": "oklch(0.469 0.084 257.657)" },
+                "700": { "value": "oklch(0.399 0.084 257.85)" },
+                "800": { "value": "oklch(0.324 0.072 260.329)" },
+                "900": { "value": "oklch(0.259 0.062 265.566)" },
+                "950": { "value": "oklch(0.179 0.05 265.487)" }
+            }
+        }
+    }
+}
+"""
 
 API_CONFIG_KEYS = [
     "enable_swagger_ui",
@@ -59,6 +81,7 @@ def get_configs() -> ConfigResponse:
         "dashboard_alert": [alert for alert in DASHBOARD_UIALERTS if 
isinstance(alert, UIAlert)],
         "show_external_log_redirect": task_log_reader.supports_external_link,
         "external_log_name": getattr(task_log_reader.log_handler, "log_name", 
None),
+        "theme": loads(conf.get("api", "theme", fallback=THEME_FALLBACK)),
     }
 
     config.update({key: value for key, value in additional_config.items()})
diff --git a/airflow-core/src/airflow/config_templates/config.yml 
b/airflow-core/src/airflow/config_templates/config.yml
index a8412155042..56136680cfa 100644
--- a/airflow-core/src/airflow/config_templates/config.yml
+++ b/airflow-core/src/airflow/config_templates/config.yml
@@ -1368,6 +1368,66 @@ api:
       type: string
       example: ~
       default:
+    theme:
+      description: |
+        JSON config to customize the Chakra UI theme.
+        Currently only supports ``brand`` color customization.
+
+        Must supply ``50``-``950`` OKLCH color values for ``brand`` color.
+        For usage see :ref:`customizing-ui-theme`
+
+        .. important::
+          ``oklch(l c h)`` must follow next format:
+
+          - l (lightness) : ``float`` Must be between 0 and 1
+          - c (chroma) : ``float`` Must be between 0 and 0.5
+          - h (hue) : ``float`` Must be between 0 and 360
+
+        Note: As shown below, you can split your json config over multiple 
lines by indenting.
+        See configparser documentation for an example:
+        
https://docs.python.org/3/library/configparser.html#supported-ini-file-structure.
+      version_added: ~
+      type: string
+      example: >
+        {
+              "tokens": {
+                "colors": {
+                  "brand": {
+                    "50": { "value": "oklch(0.971 0.013 17.38)" },
+                    "100": { "value": "oklch(0.936 0.032 17.717)" },
+                    "200": { "value": "oklch(0.885 0.062 18.334)" },
+                    "300": { "value": "oklch(0.808 0.114 19.571)" },
+                    "400": { "value": "oklch(0.704 0.191 22.216)" },
+                    "500": { "value": "oklch(0.637 0.237 25.331)" },
+                    "600": { "value": "oklch(0.577 0.245 27.325)" },
+                    "700": { "value": "oklch(0.505 0.213 27.518)" },
+                    "800": { "value": "oklch(0.444 0.177 26.899)" },
+                    "900": { "value": "oklch(0.396 0.141 25.723)" },
+                    "950": { "value": "oklch(0.258 0.092 26.042)" }
+                  }
+                }
+              }
+            }
+      default: >
+        {{
+              "tokens": {{
+                "colors": {{
+                  "brand": {{
+                    "50": {{ "value": "oklch(0.98 0.006 248.717)" }},
+                    "100": {{ "value": "oklch(0.962 0.012 249.460)" }},
+                    "200": {{ "value": "oklch(0.923 0.023 255.082)" }},
+                    "300": {{ "value": "oklch(0.865 0.039 252.420)" }},
+                    "400": {{ "value": "oklch(0.705 0.066 256.378)" }},
+                    "500": {{ "value": "oklch(0.575 0.08 257.759)" }},
+                    "600": {{ "value": "oklch(0.469 0.084 257.657)" }},
+                    "700": {{ "value": "oklch(0.399 0.084 257.850)" }},
+                    "800": {{ "value": "oklch(0.324 0.072 260.329)" }},
+                    "900": {{ "value": "oklch(0.259 0.062 265.566)" }},
+                    "950": {{ "value": "oklch(0.179 0.05 265.487)" }}
+                  }}
+                }}
+              }}
+            }}
     enable_swagger_ui:
       description: |
         Boolean for running SwaggerUI in the webserver.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
index 5a5f9e3d220..440ea0b902b 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
@@ -7102,10 +7102,13 @@ export const $ConfigResponse = {
                 }
             ],
             title: 'External Log Name'
+        },
+        theme: {
+            '$ref': '#/components/schemas/Theme'
         }
     },
     type: 'object',
-    required: ['page_size', 'auto_refresh_interval', 
'hide_paused_dags_by_default', 'instance_name', 'enable_swagger_ui', 
'require_confirmation_dag_change', 'default_wrap', 'test_connection', 
'dashboard_alert', 'show_external_log_redirect'],
+    required: ['page_size', 'auto_refresh_interval', 
'hide_paused_dags_by_default', 'instance_name', 'enable_swagger_ui', 
'require_confirmation_dag_change', 'default_wrap', 'test_connection', 
'dashboard_alert', 'show_external_log_redirect', 'theme'],
     title: 'ConfigResponse',
     description: 'configuration serializer.'
 } as const;
@@ -8068,6 +8071,10 @@ export const $NodeResponse = {
     description: 'Node serializer for responses.'
 } as const;
 
+export const $OklchColor = {
+    type: 'string'
+} as const;
+
 export const $StandardHookFields = {
     properties: {
         description: {
@@ -8254,6 +8261,43 @@ export const $TeamResponse = {
     description: 'Base serializer for Team.'
 } as const;
 
+export const $Theme = {
+    properties: {
+        tokens: {
+            additionalProperties: {
+                additionalProperties: {
+                    additionalProperties: {
+                        additionalProperties: {
+                            '$ref': '#/components/schemas/OklchColor'
+                        },
+                        propertyNames: {
+                            const: 'value'
+                        },
+                        type: 'object'
+                    },
+                    propertyNames: {
+                        enum: ['50', '100', '200', '300', '400', '500', '600', 
'700', '800', '900', '950']
+                    },
+                    type: 'object'
+                },
+                propertyNames: {
+                    const: 'brand'
+                },
+                type: 'object'
+            },
+            propertyNames: {
+                const: 'colors'
+            },
+            type: 'object',
+            title: 'Tokens'
+        }
+    },
+    type: 'object',
+    required: ['tokens'],
+    title: 'Theme',
+    description: "JSON to modify Chakra's theme."
+} as const;
+
 export const $UIAlert = {
     properties: {
         text: {
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
index 18a3056024d..da93b544463 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
@@ -1767,6 +1767,7 @@ export type ConfigResponse = {
     dashboard_alert: Array<UIAlert>;
     show_external_log_redirect: boolean;
     external_log_name?: string | null;
+    theme: Theme;
 };
 
 /**
@@ -1999,6 +2000,8 @@ export type NodeResponse = {
     asset_condition_type?: 'or-gate' | 'and-gate' | null;
 };
 
+export type OklchColor = string;
+
 /**
  * Standard fields of a Hook that a form will render.
  */
@@ -2053,6 +2056,21 @@ export type TeamResponse = {
     name: string;
 };
 
+/**
+ * JSON to modify Chakra's theme.
+ */
+export type Theme = {
+    tokens: {
+        [key: string]: {
+            [key: string]: {
+                [key: string]: {
+                    [key: string]: OklchColor;
+                };
+            };
+        };
+    };
+};
+
 /**
  * Optional alert to be shown at the top of the page.
  */
diff --git a/airflow-core/src/airflow/ui/src/context/ChakraCustomProvider.tsx 
b/airflow-core/src/airflow/ui/src/context/ChakraCustomProvider.tsx
new file mode 100644
index 00000000000..1c1c7b88a63
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/context/ChakraCustomProvider.tsx
@@ -0,0 +1,38 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { ChakraProvider } from "@chakra-ui/react";
+import { useMemo, type PropsWithChildren } from "react";
+
+import type { Theme } from "openapi/requests/types.gen";
+import { useConfig } from "src/queries/useConfig";
+import { createTheme } from "src/theme";
+
+export const ChakraCustomProvider = ({ children }: PropsWithChildren) => {
+  const theme = useConfig("theme");
+
+  const system = useMemo(() => {
+    if (typeof theme === "undefined") {
+      return undefined;
+    }
+
+    return createTheme(theme as Theme);
+  }, [theme]);
+
+  return system && <ChakraProvider value={system}>{children}</ChakraProvider>;
+};
diff --git a/airflow-core/src/airflow/ui/src/main.tsx 
b/airflow-core/src/airflow/ui/src/main.tsx
index a98de89b486..abd40e064d4 100644
--- a/airflow-core/src/airflow/ui/src/main.tsx
+++ b/airflow-core/src/airflow/ui/src/main.tsx
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { ChakraProvider } from "@chakra-ui/react";
 import { QueryClientProvider } from "@tanstack/react-query";
 import axios, { type AxiosError } from "axios";
 import { StrictMode } from "react";
@@ -29,6 +28,7 @@ import * as ReactRouterDOM from "react-router-dom";
 import * as ReactJSXRuntime from "react/jsx-runtime";
 
 import type { HTTPExceptionResponse } from "openapi/requests/types.gen";
+import { ChakraCustomProvider } from "src/context/ChakraCustomProvider";
 import { ColorModeProvider } from "src/context/colorMode";
 import { TimezoneProvider } from "src/context/timezone";
 import { router } from "src/router";
@@ -36,7 +36,6 @@ import { getRedirectPath } from "src/utils/links.ts";
 
 import i18n from "./i18n/config";
 import { client } from "./queryClient";
-import { system } from "./theme";
 
 // Set React, ReactDOM, and ReactJSXRuntime on globalThis to share them with 
the dynamically imported React plugins.
 // Only one instance of React should be used.
@@ -69,15 +68,15 @@ axios.interceptors.response.use(
 createRoot(document.querySelector("#root") as HTMLDivElement).render(
   <StrictMode>
     <I18nextProvider i18n={i18n}>
-      <ChakraProvider value={system}>
-        <ColorModeProvider>
-          <QueryClientProvider client={client}>
+      <QueryClientProvider client={client}>
+        <ChakraCustomProvider>
+          <ColorModeProvider>
             <TimezoneProvider>
               <RouterProvider router={router} />
             </TimezoneProvider>
-          </QueryClientProvider>
-        </ColorModeProvider>
-      </ChakraProvider>
+          </ColorModeProvider>
+        </ChakraCustomProvider>
+      </QueryClientProvider>
     </I18nextProvider>
   </StrictMode>,
 );
diff --git 
a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/TaskLogHeader.tsx 
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/TaskLogHeader.tsx
index 0d8d6c88e77..85f0fc4ec0e 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/TaskLogHeader.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/TaskLogHeader.tsx
@@ -42,7 +42,7 @@ import type { TaskInstanceResponse } from 
"openapi/requests/types.gen";
 import { TaskTrySelect } from "src/components/TaskTrySelect";
 import { Button, Menu, Select, Tooltip } from "src/components/ui";
 import { SearchParamsKeys } from "src/constants/searchParams";
-import { system } from "src/theme";
+import { defaultSystem } from "src/theme";
 import { type LogLevel, logLevelColorMapping, logLevelOptions } from 
"src/utils/logs";
 
 type Props = {
@@ -89,7 +89,7 @@ export const TaskLogHeader = ({
   // Have select zIndex greater than modal zIndex in fullscreen so that
   // select options are displayed.
   const zIndex = isFullscreen
-    ? Number(system.tokens.categoryMap.get("zIndex")?.get("modal")?.value ?? 
1400) + 1
+    ? 
Number(defaultSystem.tokens.categoryMap.get("zIndex")?.get("modal")?.value ?? 
1400) + 1
     : undefined;
 
   const sourceOptionList = createListCollection<{
diff --git a/airflow-core/src/airflow/ui/src/theme.ts 
b/airflow-core/src/airflow/ui/src/theme.ts
index bd8206c11d3..266c590a3d0 100644
--- a/airflow-core/src/airflow/ui/src/theme.ts
+++ b/airflow-core/src/airflow/ui/src/theme.ts
@@ -23,6 +23,8 @@
 import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react";
 import type { CSSProperties } from "react";
 
+import type { Theme } from "openapi/requests/types.gen";
+
 const generateSemanticTokens = (color: string, darkContrast: string = "white") 
=> ({
   solid: { value: `{colors.${color}.600}` },
   contrast: { value: { _light: "white", _dark: darkContrast } },
@@ -33,371 +35,377 @@ const generateSemanticTokens = (color: string, 
darkContrast: string = "white") =
   focusRing: { value: { _light: `{colors.${color}.800}`, _dark: 
`{colors.${color}.200}` } },
 });
 
-export const customConfig = defineConfig({
+const defaultTheme = {
   // See https://chakra-ui.com/docs/theming/colors for more information on the 
colors used here.
-  theme: {
-    tokens: {
-      colors: {
-        black: { value: "oklch(0.23185 0.0323 266.44)" }, // Custom value for 
dark mode
-        brand: {
-          "50": { value: "oklch(0.98 0.006 248.717)" },
-          "100": { value: "oklch(0.962 0.012 249.460)" },
-          "200": { value: "oklch(0.923 0.023 255.082)" },
-          "300": { value: "oklch(0.865 0.039 252.420)" },
-          "400": { value: "oklch(0.705 0.066 256.378)" },
-          "500": { value: "oklch(0.575 0.08 257.759)" },
-          "600": { value: "oklch(0.469 0.084 257.657)" },
-          "700": { value: "oklch(0.399 0.084 257.850)" },
-          "800": { value: "oklch(0.324 0.072 260.329)" },
-          "900": { value: "oklch(0.259 0.062 265.566)" },
-          "950": { value: "oklch(0.179 0.05 265.487)" },
-        },
-        gray: {
-          // Values modified from original Tailwind to improve contrast in 
Chakra UI
-          "50": { value: "oklch(0.985 0.004 253)" }, // Original: oklch(0.985 
0.002 247.839)
-          "100": { value: "oklch(0.955 0.006 253)" }, // Original: oklch(0.967 
0.003 264.542)
-          "200": { value: "oklch(0.915 0.01 253)" }, // Original: oklch(0.928 
0.006 264.531)
-          "300": { value: "oklch(0.85 0.016 253)" }, // Original: oklch(0.872 
0.01 258.338)
-          "400": { value: "oklch(0.75 0.025 252)" }, // Original: oklch(0.707 
0.022 261.325)
-          "500": { value: "oklch(0.63 0.042 252)" }, // Original: oklch(0.551 
0.027 264.364)
-          "600": { value: "oklch(0.45 0.055 251)" }, // Original: oklch(0.446 
0.03 256.802)
-          "700": { value: "oklch(0.35 0.045 251)" }, // Original: oklch(0.373 
0.034 259.733)
-          "800": { value: "oklch(0.28 0.035 251)" }, // Original: oklch(0.278 
0.033 256.848)
-          "900": { value: "oklch(0.18 0.03 251)" }, // Original: oklch(0.21 
0.034 264.665)
-          "950": { value: "oklch(0.11 0.025 251)" }, // Original: oklch(0.13 
0.028 261.692)
-        },
-        // TAILWIND 4.0 COLORS
-        // See https://tailwindcss.com/docs/colors for more information on the 
colors used here.
-        red: {
-          "50": { value: "oklch(0.971 0.013 17.38)" },
-          "100": { value: "oklch(0.936 0.032 17.717)" },
-          "200": { value: "oklch(0.885 0.062 18.334)" },
-          "300": { value: "oklch(0.808 0.114 19.571)" },
-          "400": { value: "oklch(0.704 0.191 22.216)" },
-          "500": { value: "oklch(0.637 0.237 25.331)" },
-          "600": { value: "oklch(0.577 0.245 27.325)" },
-          "700": { value: "oklch(0.505 0.213 27.518)" },
-          "800": { value: "oklch(0.444 0.177 26.899)" },
-          "900": { value: "oklch(0.396 0.141 25.723)" },
-          "950": { value: "oklch(0.258 0.092 26.042)" },
-        },
+  tokens: {
+    colors: {
+      black: { value: "oklch(0.23185 0.0323 266.44)" }, // Custom value for 
dark mode
+      brand: {
+        "50": { value: "oklch(0.98 0.006 248.717)" },
+        "100": { value: "oklch(0.962 0.012 249.460)" },
+        "200": { value: "oklch(0.923 0.023 255.082)" },
+        "300": { value: "oklch(0.865 0.039 252.420)" },
+        "400": { value: "oklch(0.705 0.066 256.378)" },
+        "500": { value: "oklch(0.575 0.08 257.759)" },
+        "600": { value: "oklch(0.469 0.084 257.657)" },
+        "700": { value: "oklch(0.399 0.084 257.850)" },
+        "800": { value: "oklch(0.324 0.072 260.329)" },
+        "900": { value: "oklch(0.259 0.062 265.566)" },
+        "950": { value: "oklch(0.179 0.05 265.487)" },
+      },
+      gray: {
         // Values modified from original Tailwind to improve contrast in 
Chakra UI
-        orange: {
-          "50": { value: "oklch(0.982 0.013 83.915)" },
-          "100": { value: "oklch(0.961 0.033 82.320)" },
-          "200": { value: "oklch(0.918 0.065 79.975)" },
-          "300": { value: "oklch(0.857 0.118 76.815)" },
-          "400": { value: "oklch(0.7492 0.1439 62.081)" }, // Original: 
oklch(0.774 0.186 71.555)
-          "500": { value: "oklch(0.6462 0.1979 43.792)" }, // Original: 
oklch(0.705 0.213 47.604)
-          "600": { value: "oklch(0.5902 0.198 35.93)" }, // Original: 
oklch(0.632 0.214 41.185)
-          "700": { value: "oklch(0.553 0.184 41.777)" },
-          "800": { value: "oklch(0.469 0.144 45.164)" },
-          "900": { value: "oklch(0.414 0.110 48.717)" },
-          "950": { value: "oklch(0.271 0.069 52.345)" },
-        },
-        amber: {
-          "50": { value: "oklch(0.987 0.022 95.277)" },
-          "100": { value: "oklch(0.962 0.059 95.617)" },
-          "200": { value: "oklch(0.924 0.12 95.746)" },
-          "300": { value: "oklch(0.879 0.169 91.605)" },
-          "400": { value: "oklch(0.828 0.189 84.429)" },
-          "500": { value: "oklch(0.769 0.188 70.08)" },
-          "600": { value: "oklch(0.666 0.179 58.318)" },
-          "700": { value: "oklch(0.555 0.163 48.998)" },
-          "800": { value: "oklch(0.473 0.137 46.201)" },
-          "900": { value: "oklch(0.414 0.112 45.904)" },
-          "950": { value: "oklch(0.279 0.077 45.635)" },
-        },
-        yellow: {
-          "50": { value: "oklch(0.987 0.026 102.212)" },
-          "100": { value: "oklch(0.973 0.071 103.193)" },
-          "200": { value: "oklch(0.945 0.129 101.54)" },
-          "300": { value: "oklch(0.905 0.182 98.111)" },
-          "400": { value: "oklch(0.852 0.199 91.936)" },
-          "500": { value: "oklch(0.795 0.184 86.047)" },
-          "600": { value: "oklch(0.681 0.162 75.834)" },
-          "700": { value: "oklch(0.554 0.135 66.442)" },
-          "800": { value: "oklch(0.476 0.114 61.907)" },
-          "900": { value: "oklch(0.421 0.095 57.708)" },
-          "950": { value: "oklch(0.286 0.066 53.813)" },
-        },
-        lime: {
-          "50": { value: "oklch(0.986 0.031 120.757)" },
-          "100": { value: "oklch(0.967 0.067 122.328)" },
-          "200": { value: "oklch(0.938 0.127 124.321)" },
-          "300": { value: "oklch(0.897 0.196 126.665)" },
-          "400": { value: "oklch(0.841 0.238 128.85)" },
-          "500": { value: "oklch(0.768 0.233 130.85)" },
-          "600": { value: "oklch(0.648 0.2 131.684)" },
-          "700": { value: "oklch(0.532 0.157 131.589)" },
-          "800": { value: "oklch(0.453 0.124 130.933)" },
-          "900": { value: "oklch(0.405 0.101 131.063)" },
-          "950": { value: "oklch(0.274 0.072 132.109)" },
-        },
-        green: {
-          // Values modified from original Tailwind to improve contrast in 
Chakra UI
-          "50": { value: "oklch(0.982 0.018 155.826)" },
-          "100": { value: "oklch(0.962 0.044 156.743)" },
-          "200": { value: "oklch(0.925 0.084 155.995)" },
-          "300": { value: "oklch(0.75 0.18 153.0)" }, // Original: oklch(0.871 
0.15 154.449)
-          "400": { value: "oklch(0.625 0.209 150.0)" }, // Original: 
oklch(0.792 0.209 151.711)
-          "500": { value: "oklch(0.528 0.219 149.579)" }, // Original: 
oklch(0.723 0.219 149.579)
-          "600": { value: "oklch(0.47 0.20 149.0)" }, // Original: oklch(0.627 
0.194 149.214)
-          "700": { value: "oklch(0.40 0.16 149.5)" }, // Original: oklch(0.527 
0.154 150.069)
-          "800": { value: "oklch(0.448 0.119 151.328)" },
-          "900": { value: "oklch(0.393 0.095 152.535)" },
-          "950": { value: "oklch(0.266 0.065 152.934)" },
-        },
-        emerald: {
-          "50": { value: "oklch(0.979 0.021 166.113)" },
-          "100": { value: "oklch(0.95 0.052 163.051)" },
-          "200": { value: "oklch(0.905 0.093 164.15)" },
-          "300": { value: "oklch(0.845 0.143 164.978)" },
-          "400": { value: "oklch(0.765 0.177 163.223)" },
-          "500": { value: "oklch(0.696 0.17 162.48)" },
-          "600": { value: "oklch(0.596 0.145 163.225)" },
-          "700": { value: "oklch(0.508 0.118 165.612)" },
-          "800": { value: "oklch(0.432 0.095 166.913)" },
-          "900": { value: "oklch(0.378 0.077 168.94)" },
-          "950": { value: "oklch(0.262 0.051 172.552)" },
-        },
-        teal: {
-          "50": { value: "oklch(0.984 0.014 180.72)" },
-          "100": { value: "oklch(0.953 0.051 180.801)" },
-          "200": { value: "oklch(0.91 0.096 180.426)" },
-          "300": { value: "oklch(0.855 0.138 181.071)" },
-          "400": { value: "oklch(0.777 0.152 181.912)" },
-          "500": { value: "oklch(0.704 0.14 182.503)" },
-          "600": { value: "oklch(0.6 0.118 184.704)" },
-          "700": { value: "oklch(0.511 0.096 186.391)" },
-          "800": { value: "oklch(0.437 0.078 188.216)" },
-          "900": { value: "oklch(0.386 0.063 188.416)" },
-          "950": { value: "oklch(0.277 0.046 192.524)" },
-        },
-        cyan: {
-          "50": { value: "oklch(0.984 0.019 200.873)" },
-          "100": { value: "oklch(0.956 0.045 203.388)" },
-          "200": { value: "oklch(0.917 0.08 205.041)" },
-          "300": { value: "oklch(0.865 0.127 207.078)" },
-          "400": { value: "oklch(0.789 0.154 211.53)" },
-          "500": { value: "oklch(0.715 0.143 215.221)" },
-          "600": { value: "oklch(0.609 0.126 221.723)" },
-          "700": { value: "oklch(0.52 0.105 223.128)" },
-          "800": { value: "oklch(0.45 0.085 224.283)" },
-          "900": { value: "oklch(0.398 0.07 227.392)" },
-          "950": { value: "oklch(0.302 0.056 229.695)" },
-        },
-        sky: {
-          "50": { value: "oklch(0.977 0.013 236.62)" },
-          "100": { value: "oklch(0.951 0.026 236.824)" },
-          "200": { value: "oklch(0.901 0.058 230.902)" },
-          "300": { value: "oklch(0.828 0.111 230.318)" },
-          "400": { value: "oklch(0.746 0.16 232.661)" },
-          "500": { value: "oklch(0.685 0.169 237.323)" },
-          "600": { value: "oklch(0.588 0.158 241.966)" },
-          "700": { value: "oklch(0.5 0.134 242.749)" },
-          "800": { value: "oklch(0.443 0.11 240.79)" },
-          "900": { value: "oklch(0.391 0.09 240.876)" },
-          "950": { value: "oklch(0.293 0.066 243.157)" },
-        },
-        blue: {
-          "50": { value: "oklch(0.97 0.014 254.604)" },
-          "100": { value: "oklch(0.932 0.032 255.585)" },
-          "200": { value: "oklch(0.882 0.059 254.128)" },
-          "300": { value: "oklch(0.809 0.105 251.813)" },
-          "400": { value: "oklch(0.707 0.165 254.624)" },
-          "500": { value: "oklch(0.623 0.214 259.815)" },
-          "600": { value: "oklch(0.546 0.245 262.881)" },
-          "700": { value: "oklch(0.488 0.243 264.376)" },
-          "800": { value: "oklch(0.424 0.199 265.638)" },
-          "900": { value: "oklch(0.379 0.146 265.522)" },
-          "950": { value: "oklch(0.282 0.091 267.935)" },
-        },
-        indigo: {
-          "50": { value: "oklch(0.962 0.018 272.314)" },
-          "100": { value: "oklch(0.93 0.034 272.788)" },
-          "200": { value: "oklch(0.87 0.065 274.039)" },
-          "300": { value: "oklch(0.785 0.115 274.713)" },
-          "400": { value: "oklch(0.673 0.182 276.935)" },
-          "500": { value: "oklch(0.585 0.233 277.117)" },
-          "600": { value: "oklch(0.511 0.262 276.966)" },
-          "700": { value: "oklch(0.457 0.24 277.023)" },
-          "800": { value: "oklch(0.398 0.195 277.366)" },
-          "900": { value: "oklch(0.359 0.144 278.697)" },
-          "950": { value: "oklch(0.257 0.09 281.288)" },
-        },
-        violet: {
-          "50": { value: "oklch(0.969 0.016 293.756)" },
-          "100": { value: "oklch(0.943 0.029 294.588)" },
-          "200": { value: "oklch(0.894 0.057 293.283)" },
-          "300": { value: "oklch(0.811 0.111 293.571)" },
-          "400": { value: "oklch(0.702 0.183 293.541)" },
-          "500": { value: "oklch(0.606 0.25 292.717)" },
-          "600": { value: "oklch(0.541 0.281 293.009)" },
-          "700": { value: "oklch(0.491 0.27 292.581)" },
-          "800": { value: "oklch(0.432 0.232 292.759)" },
-          "900": { value: "oklch(0.38 0.189 293.745)" },
-          "950": { value: "oklch(0.283 0.141 291.089)" },
-        },
-        purple: {
-          "50": { value: "oklch(0.977 0.014 308.299)" },
-          "100": { value: "oklch(0.946 0.033 307.174)" },
-          "200": { value: "oklch(0.902 0.063 306.703)" },
-          "300": { value: "oklch(0.827 0.119 306.383)" },
-          "400": { value: "oklch(0.714 0.203 305.504)" },
-          "500": { value: "oklch(0.627 0.265 303.9)" },
-          "600": { value: "oklch(0.558 0.288 302.321)" },
-          "700": { value: "oklch(0.496 0.265 301.924)" },
-          "800": { value: "oklch(0.438 0.218 303.724)" },
-          "900": { value: "oklch(0.381 0.176 304.987)" },
-          "950": { value: "oklch(0.291 0.149 302.717)" },
-        },
-        fuchsia: {
-          "50": { value: "oklch(0.977 0.017 320.058)" },
-          "100": { value: "oklch(0.952 0.037 318.852)" },
-          "200": { value: "oklch(0.903 0.076 319.62)" },
-          "300": { value: "oklch(0.833 0.145 321.434)" },
-          "400": { value: "oklch(0.74 0.238 322.16)" },
-          "500": { value: "oklch(0.667 0.295 322.15)" },
-          "600": { value: "oklch(0.591 0.293 322.896)" },
-          "700": { value: "oklch(0.518 0.253 323.949)" },
-          "800": { value: "oklch(0.452 0.211 324.591)" },
-          "900": { value: "oklch(0.401 0.17 325.612)" },
-          "950": { value: "oklch(0.293 0.136 325.661)" },
-        },
-        pink: {
-          "50": { value: "oklch(0.971 0.014 343.198)" },
-          "100": { value: "oklch(0.948 0.028 342.258)" },
-          "200": { value: "oklch(0.899 0.061 343.231)" },
-          "300": { value: "oklch(0.823 0.12 346.018)" },
-          "400": { value: "oklch(0.718 0.202 349.761)" },
-          "500": { value: "oklch(0.656 0.241 354.308)" },
-          "600": { value: "oklch(0.592 0.249 0.584)" },
-          "700": { value: "oklch(0.525 0.223 3.958)" },
-          "800": { value: "oklch(0.459 0.187 3.815)" },
-          "900": { value: "oklch(0.408 0.153 2.432)" },
-          "950": { value: "oklch(0.284 0.109 3.907)" },
-        },
-        rose: {
-          "50": { value: "oklch(0.969 0.015 12.422)" },
-          "100": { value: "oklch(0.941 0.03 12.58)" },
-          "200": { value: "oklch(0.892 0.058 10.001)" },
-          "300": { value: "oklch(0.81 0.117 11.638)" },
-          "400": { value: "oklch(0.712 0.194 13.428)" },
-          "500": { value: "oklch(0.645 0.246 16.439)" },
-          "600": { value: "oklch(0.586 0.253 17.585)" },
-          "700": { value: "oklch(0.514 0.222 16.935)" },
-          "800": { value: "oklch(0.455 0.188 13.697)" },
-          "900": { value: "oklch(0.41 0.159 10.272)" },
-          "950": { value: "oklch(0.271 0.105 12.094)" },
-        },
-        slate: {
-          "50": { value: "oklch(0.984 0.003 247.858)" },
-          "100": { value: "oklch(0.968 0.007 247.896)" },
-          "200": { value: "oklch(0.929 0.013 255.508)" },
-          "300": { value: "oklch(0.869 0.022 252.894)" },
-          "400": { value: "oklch(0.704 0.04 256.788)" },
-          "500": { value: "oklch(0.554 0.046 257.417)" },
-          "600": { value: "oklch(0.446 0.043 257.281)" },
-          "700": { value: "oklch(0.372 0.044 257.287)" },
-          "800": { value: "oklch(0.279 0.041 260.031)" },
-          "900": { value: "oklch(0.208 0.042 265.755)" },
-          "950": { value: "oklch(0.129 0.042 264.695)" },
-        },
-        zinc: {
-          "50": { value: "oklch(0.985 0 0)" },
-          "100": { value: "oklch(0.967 0.001 286.375)" },
-          "200": { value: "oklch(0.92 0.004 286.32)" },
-          "300": { value: "oklch(0.871 0.006 286.286)" },
-          "400": { value: "oklch(0.705 0.015 286.067)" },
-          "500": { value: "oklch(0.552 0.016 285.938)" },
-          "600": { value: "oklch(0.442 0.017 285.786)" },
-          "700": { value: "oklch(0.37 0.013 285.805)" },
-          "800": { value: "oklch(0.274 0.006 286.033)" },
-          "900": { value: "oklch(0.21 0.006 285.885)" },
-          "950": { value: "oklch(0.141 0.005 285.823)" },
-        },
-        neutral: {
-          "50": { value: "oklch(0.985 0 0)" },
-          "100": { value: "oklch(0.97 0 0)" },
-          "200": { value: "oklch(0.922 0 0)" },
-          "300": { value: "oklch(0.87 0 0)" },
-          "400": { value: "oklch(0.708 0 0)" },
-          "500": { value: "oklch(0.556 0 0)" },
-          "600": { value: "oklch(0.439 0 0)" },
-          "700": { value: "oklch(0.371 0 0)" },
-          "800": { value: "oklch(0.269 0 0)" },
-          "900": { value: "oklch(0.205 0 0)" },
-          "950": { value: "oklch(0.145 0 0)" },
-        },
-        stone: {
-          "50": { value: "oklch(0.985 0.001 106.423)" },
-          "100": { value: "oklch(0.97 0.001 106.424)" },
-          "200": { value: "oklch(0.923 0.003 48.717)" },
-          "300": { value: "oklch(0.869 0.005 56.366)" },
-          "400": { value: "oklch(0.709 0.01 56.259)" },
-          "500": { value: "oklch(0.553 0.013 58.071)" },
-          "600": { value: "oklch(0.444 0.011 73.639)" },
-          "700": { value: "oklch(0.374 0.01 67.558)" },
-          "800": { value: "oklch(0.268 0.007 34.298)" },
-          "900": { value: "oklch(0.216 0.006 56.043)" },
-          "950": { value: "oklch(0.147 0.004 49.25)" },
-        },
+        "50": { value: "oklch(0.985 0.004 253)" }, // Original: oklch(0.985 
0.002 247.839)
+        "100": { value: "oklch(0.955 0.006 253)" }, // Original: oklch(0.967 
0.003 264.542)
+        "200": { value: "oklch(0.915 0.01 253)" }, // Original: oklch(0.928 
0.006 264.531)
+        "300": { value: "oklch(0.85 0.016 253)" }, // Original: oklch(0.872 
0.01 258.338)
+        "400": { value: "oklch(0.75 0.025 252)" }, // Original: oklch(0.707 
0.022 261.325)
+        "500": { value: "oklch(0.63 0.042 252)" }, // Original: oklch(0.551 
0.027 264.364)
+        "600": { value: "oklch(0.45 0.055 251)" }, // Original: oklch(0.446 
0.03 256.802)
+        "700": { value: "oklch(0.35 0.045 251)" }, // Original: oklch(0.373 
0.034 259.733)
+        "800": { value: "oklch(0.28 0.035 251)" }, // Original: oklch(0.278 
0.033 256.848)
+        "900": { value: "oklch(0.18 0.03 251)" }, // Original: oklch(0.21 
0.034 264.665)
+        "950": { value: "oklch(0.11 0.025 251)" }, // Original: oklch(0.13 
0.028 261.692)
       },
-    },
-    semanticTokens: {
-      colors: {
-        // Brand colors for consistent theming
-        brand: generateSemanticTokens("brand"),
-        // GENERIC STATE
-        danger: generateSemanticTokens("red"),
-        info: generateSemanticTokens("blue"),
-        warning: generateSemanticTokens("amber"),
-        error: generateSemanticTokens("red"),
-        // AIRFLOW TASK STATE
-        active: generateSemanticTokens("blue"),
-        success: generateSemanticTokens("green"),
-        failed: generateSemanticTokens("red"),
-        queued: generateSemanticTokens("stone"),
-        skipped: generateSemanticTokens("pink"),
-        up_for_reschedule: generateSemanticTokens("sky"),
-        up_for_retry: generateSemanticTokens("yellow"),
-        upstream_failed: generateSemanticTokens("orange"),
-        running: generateSemanticTokens("cyan"),
-        restarting: generateSemanticTokens("violet"),
-        deferred: generateSemanticTokens("purple"),
-        scheduled: generateSemanticTokens("zinc"),
-        none: generateSemanticTokens("gray"),
-        removed: generateSemanticTokens("slate"),
-        // TAILWIND 4.0 COLORS
-        red: generateSemanticTokens("red"),
-        orange: generateSemanticTokens("orange"),
-        amber: generateSemanticTokens("amber"),
-        yellow: generateSemanticTokens("yellow"),
-        lime: generateSemanticTokens("lime"),
-        green: generateSemanticTokens("green"),
-        emerald: generateSemanticTokens("emerald"),
-        teal: generateSemanticTokens("teal"),
-        cyan: generateSemanticTokens("cyan"),
-        sky: generateSemanticTokens("sky"),
-        blue: generateSemanticTokens("blue"),
-        indigo: generateSemanticTokens("indigo"),
-        violet: generateSemanticTokens("violet"),
-        purple: generateSemanticTokens("purple"),
-        fuchsia: generateSemanticTokens("fuchsia"),
-        pink: generateSemanticTokens("pink"),
-        rose: generateSemanticTokens("rose"),
-        slate: generateSemanticTokens("slate"),
-        gray: generateSemanticTokens("gray"),
-        zinc: generateSemanticTokens("zinc"),
-        neutral: generateSemanticTokens("neutral"),
-        stone: generateSemanticTokens("stone"),
+      // TAILWIND 4.0 COLORS
+      // See https://tailwindcss.com/docs/colors for more information on the 
colors used here.
+      red: {
+        "50": { value: "oklch(0.971 0.013 17.38)" },
+        "100": { value: "oklch(0.936 0.032 17.717)" },
+        "200": { value: "oklch(0.885 0.062 18.334)" },
+        "300": { value: "oklch(0.808 0.114 19.571)" },
+        "400": { value: "oklch(0.704 0.191 22.216)" },
+        "500": { value: "oklch(0.637 0.237 25.331)" },
+        "600": { value: "oklch(0.577 0.245 27.325)" },
+        "700": { value: "oklch(0.505 0.213 27.518)" },
+        "800": { value: "oklch(0.444 0.177 26.899)" },
+        "900": { value: "oklch(0.396 0.141 25.723)" },
+        "950": { value: "oklch(0.258 0.092 26.042)" },
+      },
+      // Values modified from original Tailwind to improve contrast in Chakra 
UI
+      orange: {
+        "50": { value: "oklch(0.982 0.013 83.915)" },
+        "100": { value: "oklch(0.961 0.033 82.320)" },
+        "200": { value: "oklch(0.918 0.065 79.975)" },
+        "300": { value: "oklch(0.857 0.118 76.815)" },
+        "400": { value: "oklch(0.7492 0.1439 62.081)" }, // Original: 
oklch(0.774 0.186 71.555)
+        "500": { value: "oklch(0.6462 0.1979 43.792)" }, // Original: 
oklch(0.705 0.213 47.604)
+        "600": { value: "oklch(0.5902 0.198 35.93)" }, // Original: 
oklch(0.632 0.214 41.185)
+        "700": { value: "oklch(0.553 0.184 41.777)" },
+        "800": { value: "oklch(0.469 0.144 45.164)" },
+        "900": { value: "oklch(0.414 0.110 48.717)" },
+        "950": { value: "oklch(0.271 0.069 52.345)" },
+      },
+      amber: {
+        "50": { value: "oklch(0.987 0.022 95.277)" },
+        "100": { value: "oklch(0.962 0.059 95.617)" },
+        "200": { value: "oklch(0.924 0.12 95.746)" },
+        "300": { value: "oklch(0.879 0.169 91.605)" },
+        "400": { value: "oklch(0.828 0.189 84.429)" },
+        "500": { value: "oklch(0.769 0.188 70.08)" },
+        "600": { value: "oklch(0.666 0.179 58.318)" },
+        "700": { value: "oklch(0.555 0.163 48.998)" },
+        "800": { value: "oklch(0.473 0.137 46.201)" },
+        "900": { value: "oklch(0.414 0.112 45.904)" },
+        "950": { value: "oklch(0.279 0.077 45.635)" },
+      },
+      yellow: {
+        "50": { value: "oklch(0.987 0.026 102.212)" },
+        "100": { value: "oklch(0.973 0.071 103.193)" },
+        "200": { value: "oklch(0.945 0.129 101.54)" },
+        "300": { value: "oklch(0.905 0.182 98.111)" },
+        "400": { value: "oklch(0.852 0.199 91.936)" },
+        "500": { value: "oklch(0.795 0.184 86.047)" },
+        "600": { value: "oklch(0.681 0.162 75.834)" },
+        "700": { value: "oklch(0.554 0.135 66.442)" },
+        "800": { value: "oklch(0.476 0.114 61.907)" },
+        "900": { value: "oklch(0.421 0.095 57.708)" },
+        "950": { value: "oklch(0.286 0.066 53.813)" },
+      },
+      lime: {
+        "50": { value: "oklch(0.986 0.031 120.757)" },
+        "100": { value: "oklch(0.967 0.067 122.328)" },
+        "200": { value: "oklch(0.938 0.127 124.321)" },
+        "300": { value: "oklch(0.897 0.196 126.665)" },
+        "400": { value: "oklch(0.841 0.238 128.85)" },
+        "500": { value: "oklch(0.768 0.233 130.85)" },
+        "600": { value: "oklch(0.648 0.2 131.684)" },
+        "700": { value: "oklch(0.532 0.157 131.589)" },
+        "800": { value: "oklch(0.453 0.124 130.933)" },
+        "900": { value: "oklch(0.405 0.101 131.063)" },
+        "950": { value: "oklch(0.274 0.072 132.109)" },
+      },
+      green: {
+        // Values modified from original Tailwind to improve contrast in 
Chakra UI
+        "50": { value: "oklch(0.982 0.018 155.826)" },
+        "100": { value: "oklch(0.962 0.044 156.743)" },
+        "200": { value: "oklch(0.925 0.084 155.995)" },
+        "300": { value: "oklch(0.75 0.18 153.0)" }, // Original: oklch(0.871 
0.15 154.449)
+        "400": { value: "oklch(0.625 0.209 150.0)" }, // Original: oklch(0.792 
0.209 151.711)
+        "500": { value: "oklch(0.528 0.219 149.579)" }, // Original: 
oklch(0.723 0.219 149.579)
+        "600": { value: "oklch(0.47 0.20 149.0)" }, // Original: oklch(0.627 
0.194 149.214)
+        "700": { value: "oklch(0.40 0.16 149.5)" }, // Original: oklch(0.527 
0.154 150.069)
+        "800": { value: "oklch(0.448 0.119 151.328)" },
+        "900": { value: "oklch(0.393 0.095 152.535)" },
+        "950": { value: "oklch(0.266 0.065 152.934)" },
+      },
+      emerald: {
+        "50": { value: "oklch(0.979 0.021 166.113)" },
+        "100": { value: "oklch(0.95 0.052 163.051)" },
+        "200": { value: "oklch(0.905 0.093 164.15)" },
+        "300": { value: "oklch(0.845 0.143 164.978)" },
+        "400": { value: "oklch(0.765 0.177 163.223)" },
+        "500": { value: "oklch(0.696 0.17 162.48)" },
+        "600": { value: "oklch(0.596 0.145 163.225)" },
+        "700": { value: "oklch(0.508 0.118 165.612)" },
+        "800": { value: "oklch(0.432 0.095 166.913)" },
+        "900": { value: "oklch(0.378 0.077 168.94)" },
+        "950": { value: "oklch(0.262 0.051 172.552)" },
+      },
+      teal: {
+        "50": { value: "oklch(0.984 0.014 180.72)" },
+        "100": { value: "oklch(0.953 0.051 180.801)" },
+        "200": { value: "oklch(0.91 0.096 180.426)" },
+        "300": { value: "oklch(0.855 0.138 181.071)" },
+        "400": { value: "oklch(0.777 0.152 181.912)" },
+        "500": { value: "oklch(0.704 0.14 182.503)" },
+        "600": { value: "oklch(0.6 0.118 184.704)" },
+        "700": { value: "oklch(0.511 0.096 186.391)" },
+        "800": { value: "oklch(0.437 0.078 188.216)" },
+        "900": { value: "oklch(0.386 0.063 188.416)" },
+        "950": { value: "oklch(0.277 0.046 192.524)" },
+      },
+      cyan: {
+        "50": { value: "oklch(0.984 0.019 200.873)" },
+        "100": { value: "oklch(0.956 0.045 203.388)" },
+        "200": { value: "oklch(0.917 0.08 205.041)" },
+        "300": { value: "oklch(0.865 0.127 207.078)" },
+        "400": { value: "oklch(0.789 0.154 211.53)" },
+        "500": { value: "oklch(0.715 0.143 215.221)" },
+        "600": { value: "oklch(0.609 0.126 221.723)" },
+        "700": { value: "oklch(0.52 0.105 223.128)" },
+        "800": { value: "oklch(0.45 0.085 224.283)" },
+        "900": { value: "oklch(0.398 0.07 227.392)" },
+        "950": { value: "oklch(0.302 0.056 229.695)" },
+      },
+      sky: {
+        "50": { value: "oklch(0.977 0.013 236.62)" },
+        "100": { value: "oklch(0.951 0.026 236.824)" },
+        "200": { value: "oklch(0.901 0.058 230.902)" },
+        "300": { value: "oklch(0.828 0.111 230.318)" },
+        "400": { value: "oklch(0.746 0.16 232.661)" },
+        "500": { value: "oklch(0.685 0.169 237.323)" },
+        "600": { value: "oklch(0.588 0.158 241.966)" },
+        "700": { value: "oklch(0.5 0.134 242.749)" },
+        "800": { value: "oklch(0.443 0.11 240.79)" },
+        "900": { value: "oklch(0.391 0.09 240.876)" },
+        "950": { value: "oklch(0.293 0.066 243.157)" },
+      },
+      blue: {
+        "50": { value: "oklch(0.97 0.014 254.604)" },
+        "100": { value: "oklch(0.932 0.032 255.585)" },
+        "200": { value: "oklch(0.882 0.059 254.128)" },
+        "300": { value: "oklch(0.809 0.105 251.813)" },
+        "400": { value: "oklch(0.707 0.165 254.624)" },
+        "500": { value: "oklch(0.623 0.214 259.815)" },
+        "600": { value: "oklch(0.546 0.245 262.881)" },
+        "700": { value: "oklch(0.488 0.243 264.376)" },
+        "800": { value: "oklch(0.424 0.199 265.638)" },
+        "900": { value: "oklch(0.379 0.146 265.522)" },
+        "950": { value: "oklch(0.282 0.091 267.935)" },
+      },
+      indigo: {
+        "50": { value: "oklch(0.962 0.018 272.314)" },
+        "100": { value: "oklch(0.93 0.034 272.788)" },
+        "200": { value: "oklch(0.87 0.065 274.039)" },
+        "300": { value: "oklch(0.785 0.115 274.713)" },
+        "400": { value: "oklch(0.673 0.182 276.935)" },
+        "500": { value: "oklch(0.585 0.233 277.117)" },
+        "600": { value: "oklch(0.511 0.262 276.966)" },
+        "700": { value: "oklch(0.457 0.24 277.023)" },
+        "800": { value: "oklch(0.398 0.195 277.366)" },
+        "900": { value: "oklch(0.359 0.144 278.697)" },
+        "950": { value: "oklch(0.257 0.09 281.288)" },
+      },
+      violet: {
+        "50": { value: "oklch(0.969 0.016 293.756)" },
+        "100": { value: "oklch(0.943 0.029 294.588)" },
+        "200": { value: "oklch(0.894 0.057 293.283)" },
+        "300": { value: "oklch(0.811 0.111 293.571)" },
+        "400": { value: "oklch(0.702 0.183 293.541)" },
+        "500": { value: "oklch(0.606 0.25 292.717)" },
+        "600": { value: "oklch(0.541 0.281 293.009)" },
+        "700": { value: "oklch(0.491 0.27 292.581)" },
+        "800": { value: "oklch(0.432 0.232 292.759)" },
+        "900": { value: "oklch(0.38 0.189 293.745)" },
+        "950": { value: "oklch(0.283 0.141 291.089)" },
+      },
+      purple: {
+        "50": { value: "oklch(0.977 0.014 308.299)" },
+        "100": { value: "oklch(0.946 0.033 307.174)" },
+        "200": { value: "oklch(0.902 0.063 306.703)" },
+        "300": { value: "oklch(0.827 0.119 306.383)" },
+        "400": { value: "oklch(0.714 0.203 305.504)" },
+        "500": { value: "oklch(0.627 0.265 303.9)" },
+        "600": { value: "oklch(0.558 0.288 302.321)" },
+        "700": { value: "oklch(0.496 0.265 301.924)" },
+        "800": { value: "oklch(0.438 0.218 303.724)" },
+        "900": { value: "oklch(0.381 0.176 304.987)" },
+        "950": { value: "oklch(0.291 0.149 302.717)" },
+      },
+      fuchsia: {
+        "50": { value: "oklch(0.977 0.017 320.058)" },
+        "100": { value: "oklch(0.952 0.037 318.852)" },
+        "200": { value: "oklch(0.903 0.076 319.62)" },
+        "300": { value: "oklch(0.833 0.145 321.434)" },
+        "400": { value: "oklch(0.74 0.238 322.16)" },
+        "500": { value: "oklch(0.667 0.295 322.15)" },
+        "600": { value: "oklch(0.591 0.293 322.896)" },
+        "700": { value: "oklch(0.518 0.253 323.949)" },
+        "800": { value: "oklch(0.452 0.211 324.591)" },
+        "900": { value: "oklch(0.401 0.17 325.612)" },
+        "950": { value: "oklch(0.293 0.136 325.661)" },
+      },
+      pink: {
+        "50": { value: "oklch(0.971 0.014 343.198)" },
+        "100": { value: "oklch(0.948 0.028 342.258)" },
+        "200": { value: "oklch(0.899 0.061 343.231)" },
+        "300": { value: "oklch(0.823 0.12 346.018)" },
+        "400": { value: "oklch(0.718 0.202 349.761)" },
+        "500": { value: "oklch(0.656 0.241 354.308)" },
+        "600": { value: "oklch(0.592 0.249 0.584)" },
+        "700": { value: "oklch(0.525 0.223 3.958)" },
+        "800": { value: "oklch(0.459 0.187 3.815)" },
+        "900": { value: "oklch(0.408 0.153 2.432)" },
+        "950": { value: "oklch(0.284 0.109 3.907)" },
+      },
+      rose: {
+        "50": { value: "oklch(0.969 0.015 12.422)" },
+        "100": { value: "oklch(0.941 0.03 12.58)" },
+        "200": { value: "oklch(0.892 0.058 10.001)" },
+        "300": { value: "oklch(0.81 0.117 11.638)" },
+        "400": { value: "oklch(0.712 0.194 13.428)" },
+        "500": { value: "oklch(0.645 0.246 16.439)" },
+        "600": { value: "oklch(0.586 0.253 17.585)" },
+        "700": { value: "oklch(0.514 0.222 16.935)" },
+        "800": { value: "oklch(0.455 0.188 13.697)" },
+        "900": { value: "oklch(0.41 0.159 10.272)" },
+        "950": { value: "oklch(0.271 0.105 12.094)" },
+      },
+      slate: {
+        "50": { value: "oklch(0.984 0.003 247.858)" },
+        "100": { value: "oklch(0.968 0.007 247.896)" },
+        "200": { value: "oklch(0.929 0.013 255.508)" },
+        "300": { value: "oklch(0.869 0.022 252.894)" },
+        "400": { value: "oklch(0.704 0.04 256.788)" },
+        "500": { value: "oklch(0.554 0.046 257.417)" },
+        "600": { value: "oklch(0.446 0.043 257.281)" },
+        "700": { value: "oklch(0.372 0.044 257.287)" },
+        "800": { value: "oklch(0.279 0.041 260.031)" },
+        "900": { value: "oklch(0.208 0.042 265.755)" },
+        "950": { value: "oklch(0.129 0.042 264.695)" },
+      },
+      zinc: {
+        "50": { value: "oklch(0.985 0 0)" },
+        "100": { value: "oklch(0.967 0.001 286.375)" },
+        "200": { value: "oklch(0.92 0.004 286.32)" },
+        "300": { value: "oklch(0.871 0.006 286.286)" },
+        "400": { value: "oklch(0.705 0.015 286.067)" },
+        "500": { value: "oklch(0.552 0.016 285.938)" },
+        "600": { value: "oklch(0.442 0.017 285.786)" },
+        "700": { value: "oklch(0.37 0.013 285.805)" },
+        "800": { value: "oklch(0.274 0.006 286.033)" },
+        "900": { value: "oklch(0.21 0.006 285.885)" },
+        "950": { value: "oklch(0.141 0.005 285.823)" },
+      },
+      neutral: {
+        "50": { value: "oklch(0.985 0 0)" },
+        "100": { value: "oklch(0.97 0 0)" },
+        "200": { value: "oklch(0.922 0 0)" },
+        "300": { value: "oklch(0.87 0 0)" },
+        "400": { value: "oklch(0.708 0 0)" },
+        "500": { value: "oklch(0.556 0 0)" },
+        "600": { value: "oklch(0.439 0 0)" },
+        "700": { value: "oklch(0.371 0 0)" },
+        "800": { value: "oklch(0.269 0 0)" },
+        "900": { value: "oklch(0.205 0 0)" },
+        "950": { value: "oklch(0.145 0 0)" },
+      },
+      stone: {
+        "50": { value: "oklch(0.985 0.001 106.423)" },
+        "100": { value: "oklch(0.97 0.001 106.424)" },
+        "200": { value: "oklch(0.923 0.003 48.717)" },
+        "300": { value: "oklch(0.869 0.005 56.366)" },
+        "400": { value: "oklch(0.709 0.01 56.259)" },
+        "500": { value: "oklch(0.553 0.013 58.071)" },
+        "600": { value: "oklch(0.444 0.011 73.639)" },
+        "700": { value: "oklch(0.374 0.01 67.558)" },
+        "800": { value: "oklch(0.268 0.007 34.298)" },
+        "900": { value: "oklch(0.216 0.006 56.043)" },
+        "950": { value: "oklch(0.147 0.004 49.25)" },
       },
     },
   },
-});
+  semanticTokens: {
+    colors: {
+      // Brand colors for consistent theming
+      brand: generateSemanticTokens("brand"),
+      // GENERIC STATE
+      danger: generateSemanticTokens("red"),
+      info: generateSemanticTokens("blue"),
+      warning: generateSemanticTokens("amber"),
+      error: generateSemanticTokens("red"),
+      // AIRFLOW TASK STATE
+      active: generateSemanticTokens("blue"),
+      success: generateSemanticTokens("green"),
+      failed: generateSemanticTokens("red"),
+      queued: generateSemanticTokens("stone"),
+      skipped: generateSemanticTokens("pink"),
+      up_for_reschedule: generateSemanticTokens("sky"),
+      up_for_retry: generateSemanticTokens("yellow"),
+      upstream_failed: generateSemanticTokens("orange"),
+      running: generateSemanticTokens("cyan"),
+      restarting: generateSemanticTokens("violet"),
+      deferred: generateSemanticTokens("purple"),
+      scheduled: generateSemanticTokens("zinc"),
+      none: generateSemanticTokens("gray"),
+      removed: generateSemanticTokens("slate"),
+      // TAILWIND 4.0 COLORS
+      red: generateSemanticTokens("red"),
+      orange: generateSemanticTokens("orange"),
+      amber: generateSemanticTokens("amber"),
+      yellow: generateSemanticTokens("yellow"),
+      lime: generateSemanticTokens("lime"),
+      green: generateSemanticTokens("green"),
+      emerald: generateSemanticTokens("emerald"),
+      teal: generateSemanticTokens("teal"),
+      cyan: generateSemanticTokens("cyan"),
+      sky: generateSemanticTokens("sky"),
+      blue: generateSemanticTokens("blue"),
+      indigo: generateSemanticTokens("indigo"),
+      violet: generateSemanticTokens("violet"),
+      purple: generateSemanticTokens("purple"),
+      fuchsia: generateSemanticTokens("fuchsia"),
+      pink: generateSemanticTokens("pink"),
+      rose: generateSemanticTokens("rose"),
+      slate: generateSemanticTokens("slate"),
+      gray: generateSemanticTokens("gray"),
+      zinc: generateSemanticTokens("zinc"),
+      neutral: generateSemanticTokens("neutral"),
+      stone: generateSemanticTokens("stone"),
+    },
+  },
+};
+
+export const createTheme = (userTheme?: Theme) => {
+  const customConfig = defineConfig({
+    theme: typeof userTheme === "undefined" ? defaultTheme : { 
...defaultTheme, ...userTheme },
+  });
+
+  return createSystem(defaultConfig, customConfig);
+};
 
-export const system = createSystem(defaultConfig, customConfig);
+export const defaultSystem = createTheme();
 
 // Utility function to resolve CSS variables to their computed values
 // See: https://github.com/chakra-ui/panda/discussions/2200
diff --git a/airflow-core/tests/unit/api_fastapi/common/test_types.py 
b/airflow-core/tests/unit/api_fastapi/common/test_types.py
new file mode 100644
index 00000000000..c56e0a2e629
--- /dev/null
+++ b/airflow-core/tests/unit/api_fastapi/common/test_types.py
@@ -0,0 +1,76 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+import pytest
+from pydantic import ValidationError
+
+from airflow.api_fastapi.common.types import OklchColor
+
+
+class TestOklchColor:
+    @pytest.mark.parametrize(
+        ("input_str", "expected"),
+        [
+            ("oklch(0.637 0.237 25.331)", (0.637, 0.237, 25.331, "oklch(0.637 
0.237 25.331)")),
+            ("oklch(1 0.230 25.331)", (1.0, 0.23, 25.331, "oklch(1.0 0.23 
25.331)")),
+        ],
+    )
+    def test_valid_oklch(self, input_str, expected):
+        color = OklchColor.model_validate(input_str)
+        assert color.lightness == pytest.approx(expected[0])
+        assert color.chroma == pytest.approx(expected[1])
+        assert color.hue == pytest.approx(expected[2])
+        assert color.model_dump() == expected[3]
+
+    @pytest.mark.parametrize(
+        ("input_str", "error_message"),
+        [
+            ("oklch(-0.1 0.15 240)", "Invalid lightness: -0.1 Must be between 
0 and 1"),
+            ("oklch(1.5 0.15 240)", "Invalid lightness: 1.5 Must be between 0 
and 1"),
+            ("oklch(0.5 -0.1 240)", "Invalid chroma: -0.1 Must be between 0 
and 0.5"),
+            ("oklch(0.5 0.6 240)", "Invalid chroma: 0.6 Must be between 0 and 
0.5"),
+            ("oklch(0.5 0.15 -10)", "Invalid hue: -10.0 Must be between 0 and 
360"),
+            ("oklch(0.5 0.15 400)", "Invalid hue: 400.0 Must be between 0 and 
360"),
+            ("rgb(255, 0, 0)", "Invalid OKLCH format: rgb(255, 0, 0) Expected 
format oklch(l c h)"),
+            ("oklch(0.5 0.15)", "Invalid OKLCH format: oklch(0.5 0.15) 
Expected format oklch(l c h)"),
+            (
+                "oklch(0.5 0.15 240 0.5)",
+                "Invalid OKLCH format: oklch(0.5 0.15 240 0.5) Expected format 
oklch(l c h)",
+            ),
+            (
+                "oklch(abc 0.15 240)",
+                "Invalid OKLCH format: oklch(abc 0.15 240) Expected format 
oklch(l c h)",
+            ),
+            (
+                "oklch(10 0. 240)",
+                "Invalid OKLCH format: oklch(10 0. 240) Expected format 
oklch(l c h)",
+            ),
+            (
+                "oklch(10 3 .240)",
+                "Invalid OKLCH format: oklch(10 3 .240) Expected format 
oklch(l c h)",
+            ),
+            (
+                "oklch(. 3 240)",
+                "Invalid OKLCH format: oklch(. 3 240) Expected format oklch(l 
c h)",
+            ),
+        ],
+    )
+    def test_invalid_oklch(self, input_str, error_message):
+        with pytest.raises(ValidationError) as exc_info:
+            OklchColor.model_validate(input_str)
+        assert error_message in str(exc_info.value)
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_config.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_config.py
index 56d37c9f891..3c5077b0b5b 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_config.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_config.py
@@ -23,6 +23,26 @@ from tests_common.test_utils.config import conf_vars
 
 pytestmark = pytest.mark.db_test
 
+THEME = {
+    "tokens": {
+        "colors": {
+            "brand": {
+                "50": {"value": "oklch(0.98 0.006 248.717)"},
+                "100": {"value": "oklch(0.962 0.012 249.46)"},
+                "200": {"value": "oklch(0.923 0.023 255.082)"},
+                "300": {"value": "oklch(0.865 0.039 252.42)"},
+                "400": {"value": "oklch(0.705 0.066 256.378)"},
+                "500": {"value": "oklch(0.575 0.08 257.759)"},
+                "600": {"value": "oklch(0.469 0.084 257.657)"},
+                "700": {"value": "oklch(0.399 0.084 257.85)"},
+                "800": {"value": "oklch(0.324 0.072 260.329)"},
+                "900": {"value": "oklch(0.259 0.062 265.566)"},
+                "950": {"value": "oklch(0.179 0.05 265.487)"},
+            }
+        }
+    }
+}
+
 mock_config_response = {
     "page_size": 100,
     "auto_refresh_interval": 3,
@@ -35,6 +55,7 @@ mock_config_response = {
     "dashboard_alert": [],
     "show_external_log_redirect": False,
     "external_log_name": None,
+    "theme": THEME,
 }
 
 
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index e28a58f4dd7..793ad35c063 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -1253,6 +1253,7 @@ od
 odbc
 odps
 ok
+oklch
 Okta
 okta
 onboarded

Reply via email to