DAX SVG measure · Status

KPI arrow and delta badge with a DAX SVG measure

Unicode arrows and conditional formatting icons get you halfway. This measure draws the arrow, the signed percentage and an optional tinted pill in one image, with a neutral band so a 0.2% wobble isn't shouted in red, and a direction switch for metrics where down is good.

By · Founder & Reliability Engineer · Updated

KPI arrow / delta badge rendered from the DAX below with sample data
Rendered from the measure below with sample data at 2× (84×24 px in Power BI). 428 characters.

Use it when

  • Every KPI shows change against a comparison: prior year, prior period or target.
  • Some KPIs are 'lower is better' (cost, churn) and need inverted colours.
  • You want the change as the new Card visual's callout image.

Skip it when

The comparison value can be zero or change sign often: a percentage change is then meaningless. Show the absolute difference instead.

Three looks

The kpi arrow / delta badge in three palettes; click one to edit it.

Data it needs

The builder asks for exactly these fields; type your own measure and column names there.

Current measure
The value being reported.
Comparison measure
Prior year, prior period or target. The delta is (current − comparison) / |comparison|.

The full DAX

Swap [Sales] and [Sales PY] for your own names.

Delta Badge (measure)
Delta Badge =
-- VizForge SVG measure: KPI delta badge.
-- Set Measure tools > Data category = Image URL, then size it under Format > Visual > Image size.
-- In the new Card visual use it as the callout image: Callout > Image > Image type: Select from data.
-- Made with the free VizForge SVG measure builder: vizforge.ai/tools/svg-measure-builder
-- Need per-point tooltips, click-to-select inside the chart or Format-pane settings? Generate it as a real custom visual: vizforge.ai/visuals
VAR _Actual = [Sales]
VAR _Compare = [Sales PY]
VAR _Delta = DIVIDE ( _Actual - _Compare, ABS ( _Compare ), BLANK () )
VAR _Good = _Delta > 0
VAR _Colour = IF ( ABS ( _Delta ) < 0.005, "%23605E5C", IF ( _Good, "%231AAB40", "%23D64554" ) )
VAR _Shape = IF (
    ABS ( _Delta ) < 0.005,
    "M5.5 11H20.9V13H5.5Z",
    IF ( _Delta > 0, "M5.5 16.6L13.2 5.9L20.9 16.6Z", "M5.5 7.4L13.2 18.1L20.9 7.4Z" )
)
RETURN
    IF (
        ISBLANK ( _Delta ),
        BLANK (),
        "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='84' height='24' viewBox='0 0 84 24'><rect x='0' y='0' width='84' height='24' rx='12' fill='"
            & _Colour
            & "' fill-opacity='0.14'/><path d='"
            & _Shape
            & "' fill='"
            & _Colour
            & "'/><text x='74.4' y='12' dy='0.35em' text-anchor='end' font-family='Segoe UI, Helvetica, Arial, sans-serif' font-size='12' font-weight='600' fill='"
            & _Colour
            & "'>"
            & SUBSTITUTE ( FORMAT ( _Delta, "+0.0%;-0.0%;0.0%", "en-US" ), "%", "%25" )
            & "</text></svg>"
    )
DAX user-defined function variant (VizForge.SvgDeltaBadge)

One-line call: Delta Badge = VizForge.SvgDeltaBadge ( [Sales], [Sales PY] )

DAX query view script
-- 1) Paste into DAX query view and choose 'Update model with changes'.
--    Needs DAX user-defined functions (generally available since the June 2026 Power BI release).
DEFINE
    /// KPI arrow / delta badge as an SVG image URL (VizForge). Optional parameters default to the colours you picked.
    FUNCTION VizForge.SvgDeltaBadge = (
            pActual : NUMERIC,
            pCompare : NUMERIC,
            pDeadband : NUMERIC = 0.005,
            pNeutralColor : STRING = "#605E5C",
            pGoodColor : STRING = "#1AAB40",
            pBadColor : STRING = "#D64554"
        ) =>
        VAR _Actual = pActual
        VAR _Compare = pCompare
        VAR _Delta = DIVIDE ( _Actual - _Compare, ABS ( _Compare ), BLANK () )
        VAR _Good = _Delta > 0
        VAR _Colour = IF (
            ABS ( _Delta ) < pDeadband,
            SUBSTITUTE ( pNeutralColor, "#", "%23" ),
            IF ( _Good, SUBSTITUTE ( pGoodColor, "#", "%23" ), SUBSTITUTE ( pBadColor, "#", "%23" ) )
        )
        VAR _Shape = IF (
            ABS ( _Delta ) < pDeadband,
            "M5.5 11H20.9V13H5.5Z",
            IF ( _Delta > 0, "M5.5 16.6L13.2 5.9L20.9 16.6Z", "M5.5 7.4L13.2 18.1L20.9 7.4Z" )
        )
        RETURN
            IF (
                ISBLANK ( _Delta ),
                BLANK (),
                "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='84' height='24' viewBox='0 0 84 24'><rect x='0' y='0' width='84' height='24' rx='12' fill='"
                    & _Colour
                    & "' fill-opacity='0.14'/><path d='"
                    & _Shape
                    & "' fill='"
                    & _Colour
                    & "'/><text x='74.4' y='12' dy='0.35em' text-anchor='end' font-family='Segoe UI, Helvetica, Arial, sans-serif' font-size='12' font-weight='600' fill='"
                    & _Colour
                    & "'>"
                    & SUBSTITUTE ( FORMAT ( _Delta, "+0.0%;-0.0%;0.0%", "en-US" ), "%", "%25" )
                    & "</text></svg>"
            )

EVALUATE { VizForge.SvgDeltaBadge ( [Sales], [Sales PY] ) }

-- 2) Then create the measure and set Measure tools > Data category = Image URL:
-- Delta Badge = VizForge.SvgDeltaBadge ( [Sales], [Sales PY] )
--    Colours and thresholds are optional parameters: pass a value after the fields to override one.
--    Pass colours as plain "#RRGGBB"; the function encodes the # for the data URI.

Placing it in a report

Use it in a table column next to the value at 24 × 84, or as the Card visual's callout image (Callout > Image, Image type: Select from data) so the badge sits beside the number. Remember the Image URL data category. All setup steps.

Gotchas

When an SVG measure isn't enough

A KPI card visual can show both values on hover and switch the comparison period from the format pane. See the KPI card custom visual for what an interactive version can do.

KPI card designs using it

Finished designs built on this pattern, from the KPI card gallery.