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

pierrejeambrun 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 60db2692bd8 Add support for globalCss to custom theme (#61161)
60db2692bd8 is described below

commit 60db2692bd85bbb37fc82cd323cf4f3cb30b5382
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Thu Jan 29 16:40:11 2026 +0100

    Add support for globalCss to custom theme (#61161)
    
    * Add support for globalCss to custom theme
    
    * Fix CI
---
 airflow-core/docs/howto/customize-ui.rst           | 32 +++++++++++++++++++++-
 .../src/airflow/api_fastapi/common/types.py        |  1 +
 .../api_fastapi/core_api/openapi/_private_ui.yaml  |  8 ++++++
 .../src/airflow/config_templates/config.yml        |  3 +-
 .../airflow/ui/openapi-gen/requests/schemas.gen.ts | 15 ++++++++++
 .../airflow/ui/openapi-gen/requests/types.gen.ts   |  5 ++++
 airflow-core/src/airflow/ui/src/theme.ts           | 17 ++++++++++--
 .../api_fastapi/core_api/routes/ui/test_config.py  | 10 ++++++-
 docs/spelling_wordlist.txt                         |  1 +
 9 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/airflow-core/docs/howto/customize-ui.rst 
b/airflow-core/docs/howto/customize-ui.rst
index 8b93b4b6178..ef330a80517 100644
--- a/airflow-core/docs/howto/customize-ui.rst
+++ b/airflow-core/docs/howto/customize-ui.rst
@@ -70,9 +70,10 @@ We can provide a JSON configuration to customize the UI.
 
 .. important::
 
-  - Currently only the ``brand`` color palette can be customized.
+  - Currently only the ``brand`` color palette and ``globalCss`` 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`
+  - There is also the ability to provide custom global CSS for a fine grained 
theme control.
 
 .. note::
 
@@ -150,6 +151,35 @@ Dark Mode
 
 .. image:: ../img/change-theme/exmaple_theme_configuration_dark_mode.png
 
+3.  To add custom CSS rules to the airflow UI, you can include a ``globalCss`` 
key in the theme configuration. More information 
https://chakra-ui.com/docs/theming/customization/global-css
+
+.. 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)" }
+        }
+      }
+    },
+    "globalCss": {
+      "button": {
+        "text-transform": "uppercase"
+      }
+    }
+  }'
+
 |
 
 Adding Dashboard Alert Messages
diff --git a/airflow-core/src/airflow/api_fastapi/common/types.py 
b/airflow-core/src/airflow/api_fastapi/common/types.py
index a09f1c9b383..c19dd632343 100644
--- a/airflow-core/src/airflow/api_fastapi/common/types.py
+++ b/airflow-core/src/airflow/api_fastapi/common/types.py
@@ -178,3 +178,4 @@ class Theme(BaseModel):
             ],
         ],
     ]
+    globalCss: dict[str, dict] | None = None
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 503f5f3dc71..7d11ce58776 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
@@ -2739,6 +2739,14 @@ components:
             const: colors
           type: object
           title: Tokens
+        globalCss:
+          anyOf:
+          - additionalProperties:
+              additionalProperties: true
+              type: object
+            type: object
+          - type: 'null'
+          title: Globalcss
       type: object
       required:
       - tokens
diff --git a/airflow-core/src/airflow/config_templates/config.yml 
b/airflow-core/src/airflow/config_templates/config.yml
index 59eb620257d..d4f2bdb54aa 100644
--- a/airflow-core/src/airflow/config_templates/config.yml
+++ b/airflow-core/src/airflow/config_templates/config.yml
@@ -1379,9 +1379,10 @@ api:
     theme:
       description: |
         JSON config to customize the Chakra UI theme.
-        Currently only supports ``brand`` color customization.
+        Currently only supports ``brand`` color customization and 
``globalCss``.
 
         Must supply ``50``-``950`` OKLCH color values for ``brand`` color.
+
         For usage see :ref:`customizing-ui-theme`
 
         .. important::
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 cf35d310853..6012fae8c8c 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
@@ -8382,6 +8382,21 @@ export const $Theme = {
             },
             type: 'object',
             title: 'Tokens'
+        },
+        globalCss: {
+            anyOf: [
+                {
+                    additionalProperties: {
+                        additionalProperties: true,
+                        type: 'object'
+                    },
+                    type: 'object'
+                },
+                {
+                    type: 'null'
+                }
+            ],
+            title: 'Globalcss'
         }
     },
     type: 'object',
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 7d679bbff9f..90e75ac0e76 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
@@ -2078,6 +2078,11 @@ export type Theme = {
             };
         };
     };
+    globalCss?: {
+    [key: string]: {
+        [key: string]: unknown;
+    };
+} | null;
 };
 
 /**
diff --git a/airflow-core/src/airflow/ui/src/theme.ts 
b/airflow-core/src/airflow/ui/src/theme.ts
index 3dfe839174c..fc9c07a99b8 100644
--- a/airflow-core/src/airflow/ui/src/theme.ts
+++ b/airflow-core/src/airflow/ui/src/theme.ts
@@ -20,7 +20,13 @@
 /* eslint-disable perfectionist/sort-objects */
 
 /* eslint-disable max-lines */
-import { createSystem, defaultConfig, defineConfig, mergeConfigs } from 
"@chakra-ui/react";
+import {
+  createSystem,
+  defaultConfig,
+  defineConfig,
+  mergeConfigs,
+  type SystemStyleObject,
+} from "@chakra-ui/react";
 import type { CSSProperties } from "react";
 
 import type { Theme } from "openapi/requests/types.gen";
@@ -400,7 +406,14 @@ const defaultAirflowTheme = {
 export const createTheme = (userTheme?: Theme) => {
   const defaultAirflowConfig = defineConfig({ theme: defaultAirflowTheme });
 
-  const userConfig = defineConfig({ theme: userTheme ?? {} });
+  const userConfig = defineConfig(
+    userTheme
+      ? {
+          theme: { tokens: userTheme.tokens },
+          globalCss: userTheme.globalCss as Record<string, SystemStyleObject>,
+        }
+      : {},
+  );
 
   const mergedConfig = mergeConfigs(defaultConfig, defaultAirflowConfig, 
userConfig);
 
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 e1b973e9855..6ffe5932fbe 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
@@ -42,7 +42,15 @@ THEME = {
                 "950": {"value": "oklch(0.179 0.05 265.487)"},
             }
         }
-    }
+    },
+    "globalCss": {
+        "button": {
+            "text-transform": "uppercase",
+        },
+        "a": {
+            "text-transform": "uppercase",
+        },
+    },
 }
 
 expected_config_response = {
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 7390ccf842c..10886aa879b 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -789,6 +789,7 @@ Gitter
 gitter
 gke
 Glassdoor
+globalCSS
 globstring
 glyphicon
 Gmail

Reply via email to