Adding Interactive Charts in Astro

Recently, I revamped my website to focus more on blogs. This included adding a search bar to enhance user navigation through my content. In this post, I’ll guide you through the process of adding your own interactive charts to an Astro project using ApexCharts!

Getting Started with ApexCharts

To kick things off, we’ll utilize the ChartsComponent which we’ve designed to render ApexCharts.

Below is a basic example illustrating how to incorporate a mixed chart:

The Charts Component

Installation

First, install ApexCharts and its type definitions:

# Using npm
npm install apexcharts @types/apexcharts

# Using yarn
yarn add apexcharts @types/apexcharts

Basic Setup

ApexCharts requires that each chart has a unique container ID to render correctly. If multiple charts are using the same ID (‘#chart’), they may interfere with each other.

You can modify the ChartsComponent.astro to accept an additional id property:

Create a new component file ChartsComponent.astro:

---
// ChartsComponent.astro
interface Props {
  chart: string;
  chartId: string;
  title?: string;
  description?: string;
}

const { chart, chartId, title, description } = Astro.props;
---

<div class="chart-container w-full h-[400px] p-4 bg-white rounded-lg shadow-md">
  {title && <h2 id={`${chartId}-title`} class="text-lg font-semibold mb-2">{title}</h2>}
  {description && <p id={`${chartId}-desc`} class="text-sm text-gray-600 mb-4">{description}</p>}
  <div 
    id={chartId}
    role="img"
    aria-labelledby={title ? `${chartId}-title` : undefined}
    aria-describedby={description ? `${chartId}-desc` : undefined}
  ></div>
</div>

<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

<script is:inline define:vars={{ chartData: chart, chartId }}>
try {
  const options = JSON.parse(chartData);
  
  // Add default accessibility options
  options.chart = {
    ...options.chart,
    animations: {
      enabled: true,
      easing: 'easeinout',
      speed: 800,
      animateGradually: {
        enabled: true,
        delay: 150
      },
      dynamicAnimation: {
        enabled: true,
        speed: 350
      }
    },
    accessibility: {
      enabled: true,
      announceNewData: {
        enabled: true,
        announcementPolicy: 'all'
      }
    }
  };

  document.addEventListener('DOMContentLoaded', function() {
    const chart = new ApexCharts(document.querySelector(`#${chartId}`), options);
    chart.render().catch(console.error);
  });
} catch (error) {
  console.error('Error rendering chart:', error);
  document.querySelector(`#${chartId}`)?.insertAdjacentHTML(
    'beforeend',
    '<div class="text-red-500">Error rendering chart. Please check console for details.</div>'
  );
}
</script>

<style>
.chart-container {
  min-height: 400px;
  /* Ensure contrast for accessibility */
  --chart-background: theme('colors.white');
  --chart-text: theme('colors.gray.900');
}

@media (prefers-reduced-motion: reduce) {
  .chart-container {
    --chart-animation-duration: 0s;
  }
}
</style>

Functionality Breakdown

This component performs the following functions:

Rendering Multiple Charts

<ChartsComponent 
  chartId="line-chart"
  chart={`
    {
      "chart": {
        "type": "line"
      },
      "series": [{
        "name": "sales",
        "data": [30, 40, 35, 50, 49, 60, 70, 91, 125]
      }],
      "xaxis": {
        "categories": [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
      }
    }
  `} 
/>

When you render the **ChartsComponent, provide a unique ID for each chart:

Here’s is the end result: :D

Tip: Ensure your chart configuration is properly stringified JSON. The container has a fixed height of 400px—you can adjust this in both the div class and style section. The component will automatically adapt to your Tailwind theme. The chart will be responsive within its container.

Conclusion

And there you have it! :D

Adding interactive charts to your Astro project isn’t just a technical task; it’s a chance to make your data come alive and engage your visitors in a whole new way. I’ve loved integrating ApexCharts into my site, and I hope you found this guide helpfu.


Disclaimer: This post is for personal use, but I hope it can also help others. I'm sharing my thoughts and experiences here.
If you have any insights or feedback, please reach out!
Note: Some content on this site may have been formatted using AI.

© 2024 Pavlin

Instagram GitHub