> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting Started

> Learn the basics of amCharts 5 and how to apply Anvil2 themes to your charts in React.

export const LiveCode = ({children, customHeight, clickToLoad, example, fullWidth, fullHeight, hideCodeInLiveCode, screenshot, screenshotOnly, showCode: showCodeProp}) => {
  const SCREENSHOTS_BASE = "https://servicetitan.github.io/anvil2-docs-live-code/screenshots";
  const STACKBLITZ_BASE = "https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples";
  const [showCodeBlock, setShowCodeBlock] = useState(showCodeProp ?? false);
  const [isLocalOverride, setIsLocalOverride] = useState(false);
  useEffect(() => {
    const examplePath = `/images/live-code-screenshots-tmp/${example}.png`;
    fetch(examplePath, {
      method: "HEAD"
    }).then(r => {
      if (r.ok) setIsLocalOverride(true);
    }).catch(() => {});
  }, [example]);
  const screenshotBase = isLocalOverride ? "/images/live-code-screenshots-tmp" : SCREENSHOTS_BASE;
  if (screenshotOnly) {
    return <Frame className="flex flex-col">
        <div className="flex dark:hidden" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined,
      background: "#FFFFFF"
    }}>
          <img srcset={`${screenshotBase}/${example}.png, ${screenshotBase}/${example}-2x.png 2x`} src={`${screenshotBase}/${example}.png`} alt={example} noZoom />
        </div>
        <div className="hidden dark:flex" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined,
      background: "#141414"
    }}>
          <img srcset={`${screenshotBase}/${example}-dark.png, ${screenshotBase}/${example}-dark-2x.png 2x`} src={`${screenshotBase}/${example}-dark.png`} alt={example} noZoom />
        </div>
      </Frame>;
  }
  if (screenshot) {
    return <Frame className="flex flex-col -mb-2">
        <div className="flex dark:hidden bg-white dark:bg-codeblock border border-gray-950/10 dark:border-white/10 dark:twoslash-dark rounded-2xl overflow-hidden" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined
    }}>
          <img srcset={`${screenshotBase}/${example}.png, ${screenshotBase}/${example}-2x.png 2x`} src={`${screenshotBase}/${example}.png`} alt={example} noZoom />
        </div>

        <div className="hidden dark:flex bg-white dark:bg-codeblock border border-gray-950/10 dark:border-white/10 dark:twoslash-dark rounded-2xl overflow-hidden" style={{
      background: "#141414",
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined
    }}>
          <img srcset={`${screenshotBase}/${example}-dark.png, ${screenshotBase}/${example}-dark-2x.png 2x`} src={`${screenshotBase}/${example}-dark.png`} alt={example} noZoom />
        </div>

        <div className="flex justify-end items-center text-xs py-2 px-1 gap-4">
          {!showCodeProp ? <button className="inline-flex justify-end items-center text-gray-700 dark:text-gray-50 hover:text-blue-500 dark:hover:text-blue-300 transition-colors group self-end gap-1 cursor-pointer" onClick={() => setShowCodeBlock(!showCodeBlock)} style={{
      appearance: "none"
    }}>
              <Icon icon="code" size="12px" className="group-hover:bg-blue-500 dark:group-hover:bg-blue-300" />
              <span>{showCodeBlock ? "Hide code" : "Show code"}</span>
            </button> : null}

          <a className="inline-flex justify-end items-center hover:text-blue-500 dark:hover:text-blue-300 transition-colors group self-end gap-1" href={`${STACKBLITZ_BASE}/${example}?file=src/App.tsx`} target="_blank" rel="noreferrer">
            <Icon icon="bolt" size="12px" className="group-hover:bg-blue-500 dark:group-hover:bg-blue-300" />
            <span>StackBlitz demo</span>
          </a>
        </div>

        <div className="grid transition-[grid-template-rows] duration-300 ease-in-out overflow-auto overflow-y-hidden overflow-x-auto" style={showCodeBlock ? {
      gridTemplateRows: "1fr"
    } : {
      gridTemplateRows: "0fr"
    }}>
          <div style={{
      minHeight: 0,
      overflowX: "auto",
      overflowY: "hidden",
      marginBlockStart: "-1.25rem",
      marginBlockEnd: "-1.5rem"
    }}>
            {children}
          </div>
        </div>
      </Frame>;
  } else {
    return <div style={{
      display: "flex",
      width: fullWidth ? "100%" : "50%",
      minHeight: customHeight ? customHeight : "316px",
      resize: "vertical",
      overflow: "auto"
    }}>
        <iframe title={example} style={{
      flex: 1,
      width: fullWidth ? "100%" : "50%",
      minHeight: customHeight ? customHeight : "316px"
    }} src={`${STACKBLITZ_BASE}/${example}?embed=1&hideNavigation=1&hideExplorer=1&terminalHeight=0&file=src/App.tsx${clickToLoad ? "&ctl=1" : ""}${hideCodeInLiveCode ? "&view=preview" : ""}`} allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" />
      </div>;
  }
};

This guide covers the amCharts 5 fundamentals you need to create charts with Anvil2 themes. amCharts 5 is an imperative DOM-based library, so using it in React requires manual lifecycle management that differs from typical React component patterns.

<Note>
  For comprehensive amCharts 5 documentation, visit [amcharts.com/docs/v5](https://www.amcharts.com/docs/v5/).
</Note>

## amCharts 5 core concepts

### The root element

Every amCharts 5 chart starts with a **root element**. The root manages the chart lifecycle and is required to create every other amCharts object. Create it by passing the ID of a container `<div>`:

```tsx theme={null}
import * as am5 from "@amcharts/amcharts5";

const root = am5.Root.new("chartdiv");
```

### The `.new()` pattern

amCharts 5 uses a static `.new()` method instead of the `new` keyword to create instances. The first argument is always the root element:

```tsx theme={null}
// Create a chart
const chart = am5percent.PieChart.new(root, {
  layout: root.horizontalLayout,
  innerRadius: am5.percent(50),
});

// Create a series
const series = am5percent.PieSeries.new(root, {
  valueField: "value",
  categoryField: "category",
});
```

### Setting data

Use `setAll()` to bind data to a series. Pass an array of objects where keys match the field names you configured on the series:

```tsx theme={null}
series.data.setAll([
  { category: "Category A", value: 501 },
  { category: "Category B", value: 302 },
  { category: "Category C", value: 201 },
]);
```

### Themes

Themes control the visual appearance of chart elements. Apply themes to the root using `setThemes()`. You can combine multiple themes, and order matters — later themes override earlier ones:

```tsx theme={null}
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import { ThemeMonochrome } from "@servicetitan/anvil2-ext-charts/am5";

root.setThemes([
  am5themes_Animated.new(root),  // Adds animations
  ThemeMonochrome.new(root),     // Applies Anvil2 styles
]);
```

## Using Anvil2 themes in React

### Basic setup pattern

amCharts 5 manages its own DOM, which does not fit naturally into React's rendering model. Create the root in a `useLayoutEffect` and dispose of it on cleanup to prevent memory leaks.

In React Strict Mode, effects can run twice in development, so it's important to dispose the chart root in the cleanup function to avoid duplicate chart instances and visual glitches:

<LiveCode showCode example="ext-charts-donut-basic" fullWidth screenshot>
  ```tsx lines expandable theme={null}
  import { useLayoutEffect } from "react";
  import * as am5 from "@amcharts/amcharts5";
  import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
  import * as am5percent from "@amcharts/amcharts5/percent";
  import { ThemeMonochrome } from "@servicetitan/anvil2-ext-charts/am5";

  function App() {
    useLayoutEffect(() => {
      const data = [
        { category: "Lithuania", value: 501.9 },
        { category: "Czechia", value: 301.9 },
        { category: "Ireland", value: 201.1 },
        { category: "Germany", value: 165.8 },
      ];

      const root = am5.Root.new("chartdiv");
      root.setThemes([am5themes_Animated.new(root), ThemeMonochrome.new(root)]);

      const chart = root.container.children.push(
        am5percent.PieChart.new(root, {
          layout: root.horizontalLayout,
          innerRadius: am5.percent(50),
        }),
      );

      const series = chart.series.push(
        am5percent.PieSeries.new(root, {
          name: "Series",
          valueField: "value",
          categoryField: "category",
          legendValueText: "",
        }),
      );

      // Display percentage labels on slices
      series.labels.template.set(
        "text",
        "{valuePercentTotal.formatNumber('#.')}%",
      );

      series.data.setAll(data);

      return () => root.dispose();
    }, []);

    return <div id="chartdiv" style={{ minWidth: "55rem", height: "500px" }} />;
  }

  export default App;
  ```
</LiveCode>

### Switching themes

To use a different Anvil2 theme, swap the import:

```tsx theme={null}
// Monochrome — ordered/progressive data (default, 4 or fewer variables)
import { ThemeMonochrome } from "@servicetitan/anvil2-ext-charts/am5";

// Categorical — 5+ distinct categories
import { ThemeCategorical } from "@servicetitan/anvil2-ext-charts/am5";

// Semantic — status-based data (success, neutral, warning, danger)
import { ThemeSemantic } from "@servicetitan/anvil2-ext-charts/am5";
```

### Combining with amCharts built-in themes

Combine the Anvil2 themes with amCharts built-in themes for additional functionality. The `Animated` theme adds smooth transitions:

```tsx theme={null}
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import { ThemeCategorical } from "@servicetitan/anvil2-ext-charts/am5";

root.setThemes([
  am5themes_Animated.new(root),
  ThemeCategorical.new(root),   // Applied last so Anvil2 styles take precedence
]);
```

<Warning>
  Theme order matters. The Anvil2 theme must come after amCharts built-in themes in the array. If you place it first, the built-in theme will override Anvil2's color palette, tooltip styling, and other rules.
</Warning>

## Chart modules

amCharts 5 organizes chart types into separate modules to keep bundle sizes small. Import only the modules you need:

| Module      | Import                                | Chart types                                                 |
| ----------- | ------------------------------------- | ----------------------------------------------------------- |
| **Core**    | `@amcharts/amcharts5`                 | Root, Legend, Tooltip, Label, ColorSet                      |
| **Percent** | `@amcharts/amcharts5/percent`         | PieChart, PieSeries (donut/pie charts)                      |
| **XY**      | `@amcharts/amcharts5/xy`              | XYChart, ColumnSeries, CategoryAxis, ValueAxis (bar charts) |
| **Themes**  | `@amcharts/amcharts5/themes/Animated` | Built-in animation theme                                    |

## Next steps

* [Bar Charts](/docs/extended-libraries/charts/bar-charts) — Vertical, horizontal, grouped, and stacked bar chart examples
* [Donut Charts](/docs/extended-libraries/charts/donut-charts) — Pie and donut chart examples with legends
* [Data Visualization Guidelines](/docs/web/data-visualization) — Design guidelines for color palettes, variable ordering, and chart anatomy
* [amCharts 5 Documentation](https://www.amcharts.com/docs/v5/) — Full amCharts 5 reference
