Animated inline-SVG stacked bar chart with 2-series support, dynamic labels, auto-scaling Y-axis, value labels, and spline easing animations. 1 control, 11 properties. Renders entirely in a single Image control via data:image/svg+xml.
This component requires Modern controls to be enabled. Settings → Updates → Preview → Modern controls and themes
If your users are in a comma-decimal region, wrap the numbers
This chart draws with an SVG built by string concatenation, and Power Fx & converts numbers using the viewer’s locale. In regions that write 123,45 rather than 123.45, SVG reads that comma as a separator between two numbers and the bar x/width silently fail to draw. Axes and labels still render, because whole numbers are unaffected.
The fix is to format explicitly at the point of concatenation. In this component that means bar x/width, gridline y, and the animation delays:
- "<rect x='" & (cx - barW / 2) & "' y='" & bY & "'+ "<rect x='" & Text(cx - barW / 2, "[$-en-US]0.##") & "' y='" & bY & "'Do not repair the finished string with Substitute(s, ",", "."). That also rewrites thousands separators in your labels, turning 1,420 into 1.420, and breaks comma-separated font stacks.
# In Power Apps Studio:
1. Components tab → New component → Import from code
2. Paste the full YAML definition
3. Add the component to any screen
4. Press F5 (Preview) to trigger the entry animation// Labels: define x-axis categories
cmpStackedBarChart.Labels = Table(
{ Label: "Jan" }, { Label: "Feb" },
{ Label: "Mar" }
)
// ChartData: one row per label × series combination
cmpStackedBarChart.ChartData = Table(
{ Label: "Jan", Series: "Mobile", Value: 55 },
{ Label: "Jan", Series: "Desktop", Value: 65 },
{ Label: "Feb", Series: "Mobile", Value: 65 },
{ Label: "Feb", Series: "Desktop", Value: 55 },
{ Label: "Mar", Series: "Mobile", Value: 40 },
{ Label: "Mar", Series: "Desktop", Value: 25 }
)
// SeriesConfig: define series names and hex colors
cmpStackedBarChart.SeriesConfig = Table(
{ Series: "Mobile", Color: "#3B82F6" },
{ Series: "Desktop", Color: "#93C5FD" }
)
cmpStackedBarChart.ChartTitle = "Traffic by Device"// Shape data into Label + Series + Value rows
cmpStackedBarChart.ChartData =
ForAll(
GroupBy(
Filter(Orders, Year(Date) = 2024),
"Month", "Channel", "Group"
),
{
Label: Text(Month, "mmm"),
Series: Channel,
Value: Sum(Group, Amount)
}
)
// Map series to brand colors
cmpStackedBarChart.SeriesConfig = Table(
{ Series: "Online", Color: "#8B5CF6" },
{ Series: "In-Store", Color: "#D8B4FE" }
)cmpStackedBarChart.Theme = "Dark"
cmpStackedBarChart.Animate = false
cmpStackedBarChart.ShowValues = true
cmpStackedBarChart.ShowGrid = true
cmpStackedBarChart.ShowLegend = true
cmpStackedBarChart.ShowTitle = true
cmpStackedBarChart.ChartTitle = "Revenue Breakdown"| Property | Type | Default |
|---|---|---|
ChartDataTable with Label (text), Series (text), and Value (number) columns. One row per label × series. | Table | Jan–Jun sample |
LabelsTable with Label column defining x-axis categories. Controls bar count and label text. | Table | Jan–Jun |
SeriesConfigTable mapping each Series name to a hex Color. First row = bottom stack, second = top. | Table | Mobile #3B82F6, Desktop #93C5FD |
ChartTitleTitle text rendered at the top-left of the SVG. | Text | "Mobile / Desktop" |
Theme"Light" or "Dark". Controls background, axis, grid, and label colors. | Text | "Light" |
ShowGridShow horizontal grid lines. Y-axis labels always render regardless of this setting. | Boolean | true |
ShowLegendShow color swatches with series names at top-right. | Boolean | true |
ShowTitleShow the ChartTitle text. | Boolean | true |
ShowValuesShow stacked total above each bar. | Boolean | false |
AnimateEnable bar grow-up animation with staggered delays. | Boolean | true |
AnimationDurationDuration of each bar’s animation in seconds. | Number | 0.8 |
No output properties or events — the component is purely visual (SVG rendering). 11 input properties total.
The entire chart is a single Image control whose Image property generates a data:image/svg+xml URI. No additional dependencies — works anywhere Power Apps renders images, including galleries and PDF exports.
The Labels property defines x-axis categories. Pass 4 quarters, 6 months, or 12 departments — bars auto-space via gap = pw / CountRows(labels). Bar width adapts to label count: wider for ≤4 items (0.55 ratio), narrower for 9+ (0.42). The component iterates with Sequence(nLbl) and joins via LookUp(Data, Label = currentLabel && Series = serName)— labels without data render as zero-height bars.
Y-axis max is calculated dynamically: RoundUp(Max(Data, Value) × 2.2 / 20) × 20. This rounds to clean grid intervals with ~15% headroom. The grid divides into 5 intervals with labels always visible, even when ShowGrid = false (only the baseline renders).
Supports exactly 2 series from SeriesConfig. Series 1 (Index 1) renders as the bottom bar, series 2 (Index 2) stacks on top. Y positions: series 1 at bY - h1, series 2 at bY - h1 - h2. The top segment has rx='3' for rounded caps.
When Animate = true, bars use SVG <animate> elements with spline easing (keySplines='0.4 0 0.2 1'). Bars stagger at (barIndex - 1) × 0.06s. When Animate = false, bars render at their final position with no animation elements.
Exactly 2 series (adding a third requires modifying the formula). No interactive tooltips (inline SVG in Image controls doesn't support hover events). Empty state renders a centered “No data” message when Labels or ChartData are empty.
// Default YAML sample data
cmpStackedBarChart.ChartData = Table(
{Label:"Jan",Series:"Mobile",Value:55},
{Label:"Jan",Series:"Desktop",Value:65},
{Label:"Feb",Series:"Mobile",Value:65},
{Label:"Feb",Series:"Desktop",Value:65},
...
)
cmpStackedBarChart.SeriesConfig = Table(
{Series:"Mobile", Color:"#3B82F6"},
{Series:"Desktop", Color:"#93C5FD"}
)
cmpStackedBarChart.ChartTitle = "Mobile / Desktop"
cmpStackedBarChart.Animate = truecmpStackedBarChart.Theme = "Dark"
cmpStackedBarChart.ShowValues = true
cmpStackedBarChart.Labels = Table(
{Label:"Jan"},{Label:"Feb"},
{Label:"Mar"},{Label:"Apr"}
)
cmpStackedBarChart.SeriesConfig = Table(
{Series:"Revenue", Color:"#22C55E"},
{Series:"Costs", Color:"#4ADE80"}
)
cmpStackedBarChart.ChartTitle = "Revenue vs Costs"// Minimal sparkline-style
cmpStackedBarChart.ShowTitle = false
cmpStackedBarChart.ShowLegend = false
cmpStackedBarChart.ShowGrid = false
cmpStackedBarChart.Animate = false
cmpStackedBarChart.SeriesConfig = Table(
{Series:"Mobile", Color:"#8B5CF6"},
{Series:"Desktop", Color:"#C4B5FD"}
)| Field | Type | Notes |
|---|---|---|
| Label | Text | Category label. Must match a row in the Labels property. |
| Series | Text | Series name. Must match a row in SeriesConfig. |
| Value | Number | Numeric value. Y-axis auto-scales to the data range. |
| Field | Type | Notes |
|---|---|---|
| Label | Text | Category name displayed on x-axis. Controls bar count and ordering. |
| Field | Type | Notes |
|---|---|---|
| Series | Text | Series name matching ChartData rows. |
| Color | Text | Hex color string (e.g. "#3B82F6"). Used for bars and legend swatches. |
1 control — a single Image control rendering an inline SVG via EncodeUrl().
11 properties — all input. No output properties or events.
Default size — App.Width × 400px. SVG viewBox is 700 × 320 with 50px padding.
cmpStackedBarChart (App.Width × 400, Fill: transparent)
└── imgStackedBarChart (Image control)
└── Image = "data:image/svg+xml," & EncodeUrl(svg)
SVG structure (viewBox 700×320, padding 50):
├── <text> ChartTitle (top-left, conditional on ShowTitle)
├── <g> Legend (top-right, conditional on ShowLegend)
│ ├── <rect rx=3> + <text> Series 1 swatch
│ └── <rect rx=3> + <text> Series 2 swatch
├── Y-axis labels × 6 (always visible, auto-scaled)
├── Grid lines × 6 (conditional on ShowGrid, baseline always)
└── For each label in Labels property:
├── <text> X-axis label
├── <rect> Series 1 bar (bottom, with <animate> if enabled)
├── <rect rx=3> Series 2 bar (stacked on top)
└── <text> Value label (conditional on ShowValues)One email when something new ships. Unsubscribe anytime.
Use the toolbar to format · or type markdown directly