Skip to content

Recipes

Common patterns and solutions.

External Legend

Place the ECharts legend outside the chart:

vue
<script setup>
import { ref } from 'vue'
import type { EChartsOption } from 'shadcn-vue-echarts'

const option = ref<EChartsOption>({
  legend: {
    orient: 'vertical',
    left: 'right'
  },
  xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
  yAxis: { type: 'value' },
  series: [
    { name: 'Series 1', data: [120, 132, 101], type: 'line' },
    { name: 'Series 2', data: [90, 110, 140], type: 'line' }
  ]
})
</script>

<template>
  <Chart :option="option" />
</template>

Conditional Rendering

Show/hide charts based on conditions:

vue
<script setup>
import { ref } from 'vue'
import { ChartEmpty, ChartSkeleton } from 'shadcn-vue-echarts'

const loading = ref(true)
const hasData = ref(false)
</script>

<template>
  <div v-if="loading" class="w-full">
    <ChartSkeleton />
  </div>

  <div v-else-if="hasData" class="w-full">
    <Chart :option="option" />
  </div>

  <div v-else>
    <ChartEmpty
      title="No data available"
      description="Check back soon"
    />
  </div>
</template>

Chart Synchronization

Synchronize multiple charts via group and connectGroup:

vue
<script setup>
const option1 = ref<EChartsOption>({...})
const option2 = ref<EChartsOption>({...})
</script>

<template>
  <div class="grid grid-cols-2 gap-4">
    <Chart
      :option="option1"
      group="sync"
      connectGroup
    />
    <Chart
      :option="option2"
      group="sync"
      connectGroup
    />
  </div>
</template>

Hovering or selecting in one chart will highlight related data in the other.

Tabs Integration

Charts in different tabs:

vue
<script setup>
import { ref } from 'vue'
import type { EChartsOption } from 'shadcn-vue-echarts'

const activeTab = ref<'revenue' | 'users'>('revenue')

const revenueOption = ref<EChartsOption>({
  xAxis: { type: 'category', data: ['Jan', 'Feb', 'Mar'] },
  yAxis: { type: 'value' },
  series: [{ data: [120, 132, 101], type: 'line' }]
})

const usersOption = ref<EChartsOption>({
  xAxis: { type: 'category', data: ['Jan', 'Feb', 'Mar'] },
  yAxis: { type: 'value' },
  series: [{ data: [10000, 12000, 15000], type: 'bar' }]
})
</script>

<template>
  <div class="space-y-4">
    <div class="flex gap-2">
      <button
        @click="activeTab = 'revenue'"
        :class="{ 'bg-primary text-white': activeTab === 'revenue' }"
      >
        Revenue
      </button>
      <button
        @click="activeTab = 'users'"
        :class="{ 'bg-primary text-white': activeTab === 'users' }"
      >
        Users
      </button>
    </div>

    <Chart
      v-if="activeTab === 'revenue'"
      :option="revenueOption"
      key="revenue"
    />
    <Chart
      v-if="activeTab === 'users'"
      :option="usersOption"
      key="users"
    />
  </div>
</template>

Responsive Charts

Charts adapt to container width:

vue
<template>
  <div class="w-full h-96">
    <Chart
      :option="option"
      autoresize
      class="w-full h-full"
    />
  </div>
</template>

The autoresize prop (enabled by default) automatically calls resize() when the container changes size.

Custom Events

Listen to ECharts events:

vue
<script setup>
import { ref } from 'vue'

const events = {
  click: (params) => {
    console.log('Clicked:', params)
  },
  mouseover: (params) => {
    console.log('Hovered:', params)
  }
}
</script>

<template>
  <Chart :option="option" :events="events" />
</template>

Loading States

Show loading indicator:

vue
<script setup>
import { ref } from 'vue'

const isLoading = ref(true)

setTimeout(() => {
  isLoading.value = false
}, 2000)
</script>

<template>
  <Chart
    :option="option"
    :loading="isLoading"
  />
</template>

Or with custom loading text/color:

vue
<Chart
  :option="option"
  :loading="{
    text: 'Loading data...',
    color: 'hsl(var(--ring))',
    maskColor: 'rgba(0,0,0,0.1)'
  }"
/>

Released under the MIT License.