Skip to content

useChartTheme ​

Concrete chart colors, re-read whenever the brand color or the color mode changes. ECharts cannot take a CSS variable, so something has to resolve them.

The example below writes the brand color to the config and calls setPrimary. In a project built from the template, the config wiring makes the second call for you — see Global config.

Open in demo

Import ​

ts
import { useChartTheme } from '@shared/composables/useChartTheme'

Signature ​

ts
function useChartTheme(): {
  theme: Readonly<Ref<ChartTheme>>
}

Returns ​

MemberTypeDescription
themeReadonly<Ref<ChartTheme>>The resolved colors. Replaced wholesale on every refresh.

ChartTheme ​

KeyTypeRead fromUsed for
primarystring--sa-primary-500Series fills.
primaryLightstring--sa-primary-300The lighter half of a two-series chart.
borderstring--borderAxis and split lines.
mutedstring--muted-foregroundAxis labels and legend text.
surfacestring--sa-surface-overlayTooltip and legend background.
palettestring[]primary then five fixed huesDonuts and multi-series bars.

Example ​

vue
<script setup lang="ts">
import { useChartTheme } from '@shared/composables/useChartTheme'
import { computed } from 'vue'
import VChart from 'vue-echarts'

const { theme } = useChartTheme()

const option = computed(() => ({
  grid: { top: 16, right: 12, bottom: 24, left: 40 },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
    axisLine: { lineStyle: { color: theme.value.border } },
    axisLabel: { color: theme.value.muted },
  },
  yAxis: {
    type: 'value',
    splitLine: { lineStyle: { color: theme.value.border } },
    axisLabel: { color: theme.value.muted },
  },
  tooltip: { trigger: 'axis', backgroundColor: theme.value.surface },
  series: [{ type: 'bar', data: [820, 932, 901, 1290, 1330], itemStyle: { color: theme.value.primary } }],
}))
</script>

<template>
  <VChart :option="option" autoresize class="h-64 w-full" />
</template>

Notes ​

  • Why it exists. ECharts hands color straight to the 2D context, so every color has to be a concrete string. Reading once in onMounted leaves every chart on the page stale the moment the customizer picks a new brand color.
  • It watches isDark and config.theme.primary, and re-reads through getComputedStyle on each.
  • The refresh awaits nextTick() before reading. When the watcher fires, Vue has not yet flushed the dark class or the new variables, so a synchronous read returns the previous palette. That await is load-bearing.
  • The palette is deliberately not a ramp. Five tints of one hue cannot be told apart in a donut, so after the brand color it is five fixed categorical hues.
  • The fallbacks are used only before the first read, which is what keeps a server render or a detached DOM from producing undefined colors.
  • theme is readonly. To change the colors, change the theme.