# How Vue-Element-Admin Implements Dynamic Color Switching and SCSS Variable Theming

> Discover how Vue-Element-Admin's theme system enables dynamic color switching and SCSS variable theming. Learn to customize Element UI styles effortlessly at runtime without reloads.

- Repository: [花裤衩/vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
- Tags: deep-dive
- Published: 2026-02-27

---

**Vue-Element-Admin enables runtime theme switching by generating color clusters from SCSS variables and dynamically rewriting Element-UI's CSS in the browser without page reloads.**

PanJiaChen/vue-element-admin provides a sophisticated theme system that allows users to switch primary colors dynamically while maintaining Element-UI component consistency. The implementation combines SCSS variable preprocessing with runtime CSS manipulation to deliver instant visual updates across the entire application.

## How Dynamic Color Switching Works at Runtime

The theme system operates through a two-layer architecture: Vuex state management for persistence and a runtime CSS generator for instantaneous visual updates.

### The ThemePicker Component Architecture

The core logic resides in [`src/components/ThemePicker/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/components/ThemePicker/index.vue). This component renders an `<el-color-picker>` bound to a `theme` data property. When a user selects a new color, a watcher triggers the dynamic update chain:

```javascript
watch: {
  async theme(val) {
    const oldVal = this.theme
    if (typeof val !== 'string') return
    const themeCluster = this.getThemeCluster(val.replace('#', ''))
    const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
    // CSS replacement logic follows
  }
}

```

### Generating the Color Cluster

The `getThemeCluster` method in [`src/components/ThemePicker/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/components/ThemePicker/index.vue) generates a palette of related colors from the base primary color. It produces the base color plus ten tints (lighter variations) and one shade (darker variation):

```javascript
getThemeCluster(theme) {
  const tintColor = (color, tint) => { /* color mixing logic */ }
  const shadeColor = (color, shade) => { /* shading logic */ }
  const clusters = [theme]
  for (let i = 0; i <= 9; i++) {
    clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
  }
  clusters.push(shadeColor(theme, 0.1))
  return clusters
}

```

### Runtime CSS Injection and Replacement

The `updateStyle` method performs the actual CSS transformation. It fetches the original Element-UI theme-chalk stylesheet from unpkg if not already cached, then uses regular expressions to replace every occurrence of the old color cluster with the new cluster:

```javascript
updateStyle(style, oldCluster, newCluster) {
  let newStyle = style
  oldCluster.forEach((color, index) => {
    newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
  })
  return newStyle
}

```

The transformed CSS is then written back to the DOM via a `<style>` tag, immediately updating all Element-UI components without requiring a page reload.

## SCSS Variables That Control Element-UI Styling

The static theming foundation is defined in [`src/styles/element-variables.scss`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/styles/element-variables.scss), which overrides Element-UI's default SCSS variables before compilation.

### Primary Color Configuration in element-variables.scss

The most critical variable is `$--color-primary`, which sets the base brand color that the runtime system later manipulates:

```scss
/* theme colour */
$--color-primary: #1890ff;   // primary colour (used for buttons, tabs, etc.)
$--color-success: #13ce66;   // success state colour
$--color-warning: #ffba00;   // warning state colour
$--color-danger:  #ff4949;   // error / danger colour

```

Additional variables control typography, border colors, and table styling, but the primary color drives the dynamic theming capability.

### Exporting SCSS Variables to JavaScript

To synchronize the SCSS-defined theme with the JavaScript runtime, the file uses the `:export` pseudo-selector, which webpack's sass-loader converts into a JavaScript module:

```scss
:export {
  theme: $--color-primary;
}

```

This export is consumed by [`src/store/modules/settings.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/settings.js) to initialize the default theme state:

```javascript
import variables from '@/styles/element-variables.scss'

const state = {
  theme: variables.theme
}

```

## Integrating the Theme System with Vuex

The Vuex store in [`src/store/modules/settings.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/settings.js) persists the user's theme preference across sessions. It imports the default theme from the SCSS export and provides mutations to update the value:

```javascript
const state = {
  theme: variables.theme,
  showSettings: true,
  // ... other settings
}

const mutations = {
  CHANGE_SETTING: (state, { key, value }) => {
    if (state.hasOwnProperty(key)) {
      state[key] = value
    }
  }
}

```

The ThemePicker component emits `change` events that dispatch these mutations, ensuring the selected color survives page refreshes.

## Toggling Between Light and Custom Dark Themes

Beyond the primary color picker, the system supports a complete theme swap via the `custom-theme` class. The view in [`src/views/theme/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/theme/index.vue) provides a switch that toggles this class on the document body:

```javascript
import { toggleClass } from '@/utils'

export default {
  watch: {
    theme() {
      toggleClass(document.body, 'custom-theme')
    }
  }
}

```

The `toggleClass` helper in [`src/utils/index.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/index.js) adds or removes the class, while the pre-compiled dark theme CSS in [`src/assets/custom-theme/index.css`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/assets/custom-theme/index.css) provides the alternative styling rules.

## Summary

- **Runtime CSS Generation**: The ThemePicker component in [`src/components/ThemePicker/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/components/ThemePicker/index.vue) generates color clusters and rewrites Element-UI's CSS in real-time using `updateStyle` and `getThemeCluster`.
- **SCSS Variable Control**: The file [`src/styles/element-variables.scss`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/styles/element-variables.scss) defines `$--color-primary` and other brand colors, exporting the primary value to JavaScript via `:export` for Vuex initialization.
- **State Persistence**: The Vuex settings module stores the active theme, ensuring user preferences persist across sessions without requiring localStorage manipulation in components.
- **Binary Theme Toggle**: The `custom-theme` class mechanism in [`src/views/theme/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/theme/index.vue) allows switching to a pre-compiled dark theme via `toggleClass` from [`src/utils/index.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/utils/index.js).

## Frequently Asked Questions

### How does the theme system generate color variations automatically?

The system uses the `getThemeCluster` method in [`src/components/ThemePicker/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/components/ThemePicker/index.vue) to programmatically generate ten tint variations (lighter versions) and one shade variation (darker version) from the base primary color. These are calculated using color mixing algorithms that blend the base color with white (for tints) or black (for shades) at specific ratios, creating a full palette that matches Element-UI's expected color structure.

### What is the purpose of the `:export` block in element-variables.scss?

The `:export` pseudo-selector allows SCSS variables to be accessed from JavaScript code. When webpack processes [`src/styles/element-variables.scss`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/styles/element-variables.scss), the sass-loader converts the `:export { theme: $--color-primary; }` declaration into a JavaScript object. This enables [`src/store/modules/settings.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/store/modules/settings.js) to import the default theme value directly from the stylesheet, ensuring the Vuex state initializes with the same color defined in SCSS without hardcoding values in JavaScript.

### How can I set a permanent default theme color instead of using the runtime picker?

To set a fixed default color, modify [`src/styles/element-variables.scss`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/styles/element-variables.scss) and change the `$--color-primary` variable to your desired hex code (for example, `$--color-primary: #ff5722;`). Because this file exports the theme value to the Vuex store via `:export`, the application will initialize with your specified color. If you want to disable the runtime picker entirely, remove the `<theme-picker>` component from your layout components such as [`src/layout/components/Navbar.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/layout/components/Navbar.vue) or [`src/views/theme/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/theme/index.vue).

### What is the difference between the runtime theme picker and the custom-theme class toggle?

The **runtime theme picker** (implemented in [`src/components/ThemePicker/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/components/ThemePicker/index.vue)) performs client-side CSS manipulation to change the primary color palette in real-time without reloading, allowing any hex color to be applied instantly. In contrast, the **custom-theme class toggle** (used in [`src/views/theme/index.vue`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/views/theme/index.vue)) is a binary switch that adds or removes the `custom-theme` CSS class from the document body, which activates a pre-compiled dark theme stylesheet ([`src/assets/custom-theme/index.css`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/assets/custom-theme/index.css)). The runtime picker offers granular color control, while the class toggle provides a complete pre-built theme swap.