How to Customize AionUi's UI Using User CSS Injection Through Settings

Developers can customize AionUi's appearance by injecting custom CSS through the Settings → Display panel, which persists styles via ConfigStorage and applies them globally to the renderer process.

AionUi is an open-source UI framework that enables runtime theming without requiring application rebuilds. By leveraging user CSS injection through the settings interface, developers and end-users can override default styles, create persistent custom themes, and customize AionUi's UI appearance across sessions.

Understanding the CSS Injection Architecture

The CSS injection system in AionUi consists of three coordinated layers: storage persistence, event broadcasting, and DOM injection. This architecture ensures that custom styles survive application restarts while updating the interface in real-time when changes occur.

Storage and Persistence Layer

User-defined CSS is stored in ConfigStorage under the key customCss. The storage schema, defined in src/common/storage.ts, treats this value as a plain string that the renderer consumes at startup. When users save CSS through the settings UI, the CssThemeModal.tsx component (lines 45-57) persists the text via ConfigStorage.set('customCss', css).

Event-Driven Update Mechanism

To enable real-time updates without reloading, AionUi dispatches a custom DOM event custom-css-updated whenever CSS changes. The applyThemeCss function in src/renderer/components/CssThemeSettings/index.tsx (lines 86-95) both persists the CSS to storage and broadcasts this event with the new styles in detail.customCss.

How to Customize AionUi's UI Using the Settings Panel

The most straightforward method to inject custom CSS uses the built-in graphical interface located in the Display settings.

Accessing the CSS Theme Settings

Navigate to Settings → Display → CSS Settings to open the theme management panel. This interface, implemented in src/renderer/components/SettingsModal/contents/DisplayModalContent.tsx, embeds the CssThemeSettings component and provides controls for creating, editing, and activating CSS themes.

Creating and Saving Custom CSS

Click the + button to create a new theme, which opens CssThemeModal.tsx containing a CodeMirror editor. Paste your CSS rules into the editor—for example:

.arco-button {
  border-radius: 8px !important;
  background-color: #6366f1 !important;
}

Click Save to persist the CSS to ConfigStorage under the customCss key. The layout component immediately injects these styles into the document head.

Programmatic CSS Injection for Developers

For plugin authors or advanced use cases, AionUi exposes APIs to manipulate custom CSS programmatically without using the settings UI.

Setting Custom CSS via ConfigStorage API

You can inject CSS directly using the ConfigStorage API and dispatch the update event:

import { ConfigStorage } from '@/common/storage';

const customStyles = `
  body { background: #1e1e1e !important; }
  .arco-button-primary { background: #ff4081 !important; }
`;

async function applyCustomStyles() {
  await ConfigStorage.set('customCss', customStyles);
  window.dispatchEvent(new CustomEvent('custom-css-updated', {
    detail: { customCss: customStyles }
  }));
}
applyCustomStyles();

This approach mirrors the behavior of applyThemeCss in src/renderer/components/CssThemeSettings/index.tsx.

Listening for CSS Changes in Components

Components can react to CSS updates by listening for the custom-css-updated event:

import { useEffect, useState } from 'react';

function useCustomCss() {
  const [css, setCss] = useState('');

  useEffect(() => {
    const handler = (e: CustomEvent) => {
      setCss(e.detail?.customCss ?? '');
    };
    window.addEventListener('custom-css-updated', handler as EventListener);
    return () => window.removeEventListener('custom-css-updated', handler as EventListener);
  }, []);

  return css;
}

This hook allows any part of the renderer to synchronize with the current custom CSS state.

CSS Processing and Safety Mechanisms

AionUi processes user CSS before injection to prevent style leakage and ensure priority over default themes.

The processCustomCss Pipeline

Before injection, raw CSS passes through processCustomCss in src/renderer/utils/customCssProcessor.ts. This utility performs two operations:

  1. Selector wrapping: The wrapCustomCss function surrounds user rules with a unique selector to isolate them from built-in styles
  2. Priority enforcement: The addImportantToAll function appends !important to every declaration to ensure user styles override defaults

Automatic !important Injection

The addImportantToAll implementation (lines 14-62 in customCssProcessor.ts) parses CSS declarations and automatically injects !important flags. This guarantees that user CSS takes precedence over AionUi's default Arco Design styles without requiring manual !important typing in the editor.

Summary

  • AionUi supports user CSS injection through both a graphical settings panel and programmatic APIs
  • Custom CSS is stored in ConfigStorage under the customCss key and persists across sessions
  • The system uses a custom event (custom-css-updated) to broadcast style changes in real-time
  • The Layout component in src/renderer/layout.tsx handles actual DOM injection via a <style> tag appended to <head>
  • Safety mechanisms including selector wrapping and automatic !important injection prevent style conflicts

Frequently Asked Questions

Where is custom CSS stored in AionUi?

Custom CSS is stored in the electron-store backed ConfigStorage under the key customCss, defined in src/common/storage.ts. This storage persists between application restarts and is accessible from both the main and renderer processes.

Can I use CSS injection without using the Settings UI?

Yes. Developers can programmatically set custom CSS using ConfigStorage.set('customCss', css) and dispatch the custom-css-updated event to trigger immediate application. This approach is useful for plugins or automated theming without user interaction.

How does AionUi prevent custom CSS from breaking the interface?

AionUi processes all user CSS through processCustomCss in src/renderer/utils/customCssProcessor.ts before injection. This utility wraps selectors to isolate styles and automatically adds !important to declarations, ensuring user rules override defaults without leaking into critical UI components.

What file handles the actual injection of CSS into the document head?

The Layout component in src/renderer/layout.tsx manages DOM injection. It creates a <style id="user-defined-custom-css"> element, appends it as the last child of <head>, and updates its content whenever the custom-css-updated event fires or ConfigStorage changes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →