Skip to content

webui: add custom CSS injection via config#23904

Merged
allozaur merged 6 commits into
ggml-org:masterfrom
ServeurpersoCom:ui/custom-css
May 30, 2026
Merged

webui: add custom CSS injection via config#23904
allozaur merged 6 commits into
ggml-org:masterfrom
ServeurpersoCom:ui/custom-css

Conversation

@ServeurpersoCom
Copy link
Copy Markdown
Contributor

@ServeurpersoCom ServeurpersoCom commented May 30, 2026

Overview

Allow custom CSS injection into the WebUI via config

Additional information

Register a customCss setting in the Developer section under Custom JSON, syncable so it rides the existing ui-config pass through. inject the value into a single style element in the head, reactive on the setting. lets an operator theme a prebuilt binary through --ui-config without rebuilding, and lets a user set it from the settings panel.

Closes #23886.

Demo video

demo-css.mp4

Requirements

register a customCSS setting in the Developer section under Custom JSON,
syncable so it rides the existing ui-config pass through. inject the value
into a single style element in the head, reactive on the setting. lets an
operator theme a prebuilt binary through --ui-config without rebuilding,
and lets a user set it from the settings panel.
Comment thread tools/ui/src/lib/constants/settings-keys.ts Outdated
Comment thread tools/ui/src/routes/+layout.svelte Outdated
Comment thread tools/ui/src/lib/constants/settings-keys.ts Outdated
Comment thread tools/ui/src/lib/constants/settings-registry.ts Outdated
@ServeurpersoCom
Copy link
Copy Markdown
Contributor Author

ServeurpersoCom commented May 30, 2026

JSON sample for --ui-config

{
  "theme": "dark",
  "customCss": ":root{--background:oklch(0.985 0.018 240);--foreground:oklch(0.2 0.06 258);--card:oklch(1 0.012 240);--card-foreground:oklch(0.2 0.06 258);--popover:oklch(1 0.012 240);--popover-foreground:oklch(0.2 0.06 258);--secondary:oklch(0.93 0.035 240);--secondary-foreground:oklch(0.28 0.06 258);--muted:oklch(0.955 0.03 240);--muted-foreground:oklch(0.5 0.07 255);--accent:oklch(0.92 0.05 245);--accent-foreground:oklch(0.28 0.07 258);--code-background:oklch(0.965 0.025 240);--border:oklch(0.84 0.05 245);--input:oklch(0.89 0.04 243);--ring:oklch(0.62 0.13 258);--sidebar:oklch(0.97 0.025 240);--sidebar-foreground:oklch(0.2 0.06 258);--sidebar-accent:oklch(0.93 0.04 243);--sidebar-accent-foreground:oklch(0.28 0.07 258);--sidebar-border:oklch(0.9 0.04 243);--sidebar-ring:oklch(0.62 0.13 258);}.dark{--background:oklch(0.17 0.055 258);--foreground:oklch(0.97 0.015 255);--card:oklch(0.215 0.06 258);--card-foreground:oklch(0.97 0.015 255);--popover:oklch(0.215 0.06 258);--popover-foreground:oklch(0.97 0.015 255);--secondary:oklch(0.3 0.065 258);--secondary-foreground:oklch(0.97 0.015 255);--muted:oklch(0.28 0.06 258);--muted-foreground:oklch(0.73 0.05 255);--accent:oklch(0.33 0.085 262);--accent-foreground:oklch(0.98 0.012 255);--code-background:oklch(0.235 0.06 258);--border:oklch(0.66 0.1 260 / 38%);--input:oklch(0.66 0.1 260 / 38%);--ring:oklch(0.62 0.14 262);--sidebar:oklch(0.205 0.06 258);--sidebar-foreground:oklch(0.97 0.015 255);--sidebar-accent:oklch(0.3 0.07 260);--sidebar-accent-foreground:oklch(0.98 0.012 255);--sidebar-border:oklch(0.66 0.1 260 / 20%);--sidebar-ring:oklch(0.62 0.14 262);}"
}

@niutech
Copy link
Copy Markdown

niutech commented May 30, 2026

@ServeurpersoCom Thank you for a blazing fast patch!

@ServeurpersoCom
Copy link
Copy Markdown
Contributor Author

ServeurpersoCom commented May 30, 2026

Some nits/reviews as a team to improve our code and it's done:D

@ServeurpersoCom
Copy link
Copy Markdown
Contributor Author

ServeurpersoCom commented May 30, 2026

I check CI. A linter error on my side

move the textContent write into a use: action on the head style node.
the action is the idiomatic way to touch a node, so the no-dom-manipulating
lint rule is satisfied without a disable. value stays text through
textContent, never parsed as HTML.
@ServeurpersoCom
Copy link
Copy Markdown
Contributor Author

npm run lint no longer displays linter errors on the project. A fix is ​​needed.

@ServeurpersoCom
Copy link
Copy Markdown
Contributor Author

"npm run lint" usefull tool fixed on Follow-up PR : #23910

@ServeurpersoCom ServeurpersoCom requested a review from allozaur May 30, 2026 12:36
Comment thread tools/ui/src/lib/constants/settings-keys.ts Outdated
Comment thread tools/ui/src/routes/+layout.svelte
ServeurpersoCom and others added 2 commits May 30, 2026 15:08
Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>
…Json with migration

rename the custom config key to customJson across the type, the chat
request builder, the settings save check and the custom tools reader,
keeping the custom API param name unchanged. add a non destructive
migration that copies the legacy custom key to customJson at startup.
only render the head style tag when custom CSS is set.
@ServeurpersoCom ServeurpersoCom requested a review from allozaur May 30, 2026 13:50
@ServeurpersoCom
Copy link
Copy Markdown
Contributor Author

Please 2nd approval @ggml-org/maintainers

@allozaur allozaur merged commit d749821 into ggml-org:master May 30, 2026
5 of 6 checks passed
o7si added a commit to o7si/llama.cpp that referenced this pull request May 31, 2026
…wercase

* upstream/master: (27 commits)
  vocab : add tokenizer support for jina-embeddings-v2-base-zh (ggml-org#18756)
  ui: fix ETag truncation with MSVC compiler (ggml-org#23917)
  docs : update ZenDNN docs for Q8 support (ggml-org#23791)
  llama: only use one iGPU device by default (ggml-org#23897)
  webui: add custom CSS injection via config (ggml-org#23904)
  Support `-fa auto` in llama-bench (ggml-org#23714)
  opencl: support bf16 by converting to f16 (ggml-org#23839)
  ui: exclude generated build dirs from prettier and eslint so lint errors stop being masked (ggml-org#23910)
  TP: fix granularity for Qwen 3.5/3.6 + 3 GPUs (ggml-org#23843)
  metal : restore im2col implementation for large kernels (ggml-org#23901)
  test: (test-llama-archs) log the config name first (ggml-org#23885)
  ci : update ios-xcode release job to macos-26 (ggml-org#23906)
  ggml : add some lsx support (ggml-org#23798)
  vulkan: add Flash Attention support for BFloat16 KV cache (ggml-org#23420)
  ci : fix s390x release job (ggml-org#23898)
  ci : clear cache instead of "no timestamp" keys + fix macos (ggml-org#23895)
  llama : do not skip iGPU when only RPC devices are present (ggml-org#23868)
  server: in SSE mode, send HTTP headers when slot starts (ggml-org#23884)
  ggml-webgpu: Check earlier for WebGPU required features (ggml-org#23879)
  ggml-webgpu: add q4_0/q8_0 SET_ROWS (ggml-org#23760)
  ...

# Conflicts:
#	gguf-py/gguf/vocab.py
#	src/llama-vocab.cpp
turbo-tan pushed a commit to turbo-tan/llama.cpp-tq3 that referenced this pull request Jun 2, 2026
* webui: add custom CSS injection via config

register a customCSS setting in the Developer section under Custom JSON,
syncable so it rides the existing ui-config pass through. inject the value
into a single style element in the head, reactive on the setting. lets an
operator theme a prebuilt binary through --ui-config without rebuilding,
and lets a user set it from the settings panel.

* ui: address review from @niutech and @allozaur, rename custom JSON key and CSS field

* ui: address review from @allozaur, move custom CSS injection to a style tag in svelte:head

* ui: inject custom CSS through a svelte action instead of a bound element

move the textContent write into a use: action on the head style node.
the action is the idiomatic way to touch a node, so the no-dom-manipulating
lint rule is satisfied without a disable. value stays text through
textContent, never parsed as HTML.

* Update tools/ui/src/lib/constants/settings-keys.ts

Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>

* ui: address review from @allozaur, rename custom config key to customJson with migration

rename the custom config key to customJson across the type, the chat
request builder, the settings save check and the custom tools reader,
keeping the custom API param name unchanged. add a non destructive
migration that copies the legacy custom key to customJson at startup.
only render the head style tag when custom CSS is set.

---------

Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Allow to inject custom CSS to webUI via config

4 participants