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.
vue
<script setup lang="ts">
import { defaultConfig } from '@core/config/defaultConfig'
import { useConfig } from '@core/config/useConfig'
import { useTheme } from '@core/theme/useTheme'
import BarChart from '@shared/components/common/charts/BarChart.vue'
import { useChartTheme } from '@shared/composables/useChartTheme'
import { Button } from '@shared/components/ui/button'
import { onBeforeUnmount, onMounted } from 'vue'
const BRANDS = [defaultConfig.theme.primary, '#4f46e5', '#059669', '#e11d48']
const categories = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
const series = [{ name: 'Orders', data: [182, 231, 196, 274, 312] }]
const { theme } = useChartTheme()
const { setPrimary } = useTheme()
const cfg = useConfig()
function pick(hex: string): void {
cfg.mergeConfig({ theme: { primary: hex } })
setPrimary(hex)
}
onMounted(() => pick(defaultConfig.theme.primary))
onBeforeUnmount(() => pick(defaultConfig.theme.primary))
</script>
<template>
<div class="flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-2">
<Button
v-for="hex in BRANDS"
:key="hex"
size="sm"
variant="outline"
:aria-pressed="cfg.config.theme.primary === hex"
@click="pick(hex)"
>
{{ hex }}
</Button>
</div>
<BarChart :categories="categories" :series="series" />
<p class="sa-text-xs text-muted-foreground">
Resolved primary: <code>{{ theme.primary }}</code>
</p>
</div>
</template>Import
ts
import { useChartTheme } from '@shared/composables/useChartTheme'Signature
ts
function useChartTheme(): {
theme: Readonly<Ref<ChartTheme>>
}Returns
| Member | Type | Description |
|---|---|---|
theme | Readonly<Ref<ChartTheme>> | The resolved colors. Replaced wholesale on every refresh. |
ChartTheme
| Key | Type | Read from | Used for |
|---|---|---|---|
primary | string | --sa-primary-500 | Series fills. |
primaryLight | string | --sa-primary-300 | The lighter half of a two-series chart. |
border | string | --border | Axis and split lines. |
muted | string | --muted-foreground | Axis labels and legend text. |
surface | string | --sa-surface-overlay | Tooltip and legend background. |
palette | string[] | primary then five fixed hues | Donuts 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
colorstraight to the 2D context, so every color has to be a concrete string. Reading once inonMountedleaves every chart on the page stale the moment the customizer picks a new brand color. - It watches
isDarkandconfig.theme.primary, and re-reads throughgetComputedStyleon each. - The refresh awaits
nextTick()before reading. When the watcher fires, Vue has not yet flushed thedarkclass 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
undefinedcolors. themeis readonly. To change the colors, change the theme.
Related
- Bar chart, Donut chart, Radial gauge — the components that use it.
useTheme— where the brand color comes from.- Theming — the variables being read.