{"id":25,"date":"2026-09-08T18:40:17","date_gmt":"2026-09-08T18:40:17","guid":{"rendered":"https:\/\/www.datascientist.ca\/blog\/?p=25"},"modified":"2026-09-08T18:40:19","modified_gmt":"2026-09-08T18:40:19","slug":"prompt-playbook-kpi-card-with-background-trend-scrollable-table","status":"publish","type":"post","link":"https:\/\/www.datascientist.ca\/blog\/prompt-playbook-kpi-card-with-background-trend-scrollable-table\/","title":{"rendered":"Prompt Playbook: KPI Card with Background Trend + Scrollable Table"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Prompt Playbook: KPI Card with Background Trend + Scrollable Table<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">(Power BI HTML Content visual, built via DAX)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use this sequence when you want to recreate the pattern from scratch \u2014 a KPI<br>card that shows a headline number, a background trend line, a vs.-prior<br>comparison badge, and a scrollable table of the underlying period-by-period<br>values, all in a single HTML Content visual.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Follow the prompts roughly in this order. Each one builds on the previous<br>measure, so paste the working DAX back in if you&#8217;re starting a new chat.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Establish the base comparison measure<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;I want a KPI card that shows actual vs. last [period] and their variance \u2014<br>[metric] and previous [period]&#8217;s [metric].&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Gets you: a measure with <code>_Actual<\/code>, <code>_Prior<\/code>, <code>_Var<\/code>, <code>_VarPct<\/code> variables.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Pick the output format<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;I&#8217;m using the HTML Content visual (Regular edition) \u2014 give me the measure<br>as raw HTML.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Say this up front and skip the back-and-forth: name your visual (e.g. &#8220;HTML<br>Content&#8221; from AppSource) and edition right away. Regular unlocks CSS and<br>animation; Lite sanitizes more strictly. Getting this right early avoids<br>building the wrong output format and having to redo it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Add the background trend<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Can we also show [period] trend in the background?&#8221; \u2192 specify granularity:<br>&#8220;daily, non-cumulative&#8221; or &#8220;monthly&#8221; as needed.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Builds an <code>ADDCOLUMNS<\/code>\/<code>CONCATENATEX<\/code> table of points, plotted as an SVG<br><code>&lt;polyline&gt;<\/code> behind the card&#8217;s text.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Add the scrollable table<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Can we add a small table under it, scrollable, showing [period] and<br>[value]?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Wraps a <code>&lt;table&gt;<\/code> in a <code>&lt;div style=\"max-height:...px;overflow-y:auto;\"&gt;<\/code>,<br>reusing the same data table the sparkline already built \u2014 don&#8217;t duplicate the<br>query.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Fix the date\/period labels<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;It shows the wrong year&#8221; \u2192 &#8220;show month name and year&#8221; \u2192 &#8220;update this table<br>with month number&#8221; (for correct calendar sort order, since text month names<br>sort alphabetically by default).<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">6. Add year-level totals with month-level trend<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;We also need yearly total&#8221; \u2192 &#8220;in the background, monthly trend.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Two grains in one card: yearly headline number, monthly sparkline + monthly<br>table underneath.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Guard against misleading comparisons<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;This is only one year of data&#8221; \u2192 &#8220;so green upward doesn&#8217;t make sense here.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Add a <code>_HasPriorData<\/code> flag; show a neutral &#8220;No prior period to compare&#8221; badge<br>instead of a false increase\/decrease.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Polish: number formatting<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Round to millions&#8221; (e.g. $8.4M instead of $8,423,838).<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">9. Polish: spacing<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Remove spacing in width and height so it uses minimal real estate.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Cuts cell padding, font size, and row height for a denser table.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">10. Polish: scrollbar<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Make the scrollbar thin and unobtrusive \u2014 only appears on hover.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Adds a <code>&lt;style&gt;<\/code> block with <code>::-webkit-scrollbar<\/code> rules scoped to a class name<br>on the scroll container.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Known pitfalls to mention up front (saves a round-trip)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Long single-line string concatenations break in Tabular Editor&#8217;s editor<\/strong><br>due to auto-wrap. Fix: break <code>RETURN \"a\" &amp; \"b\" &amp; \"c\"<\/code> into a <code>VAR<\/code> holding<br>the built string, then <code>RETURN<\/code> the var \u2014 keeps each line shorter.<\/li>\n\n\n\n<li><strong><code>MonthPeriod<\/code>-style integer columns<\/strong>: confirm whether they&#8217;re a real<br><code>YYYYMM<\/code> sequential key or just a repeating 1\u201312 month index before relying<br>on <code>-1<\/code>\/<code>-12<\/code> arithmetic for &#8220;prior period.&#8221;<\/li>\n\n\n\n<li><strong>Per-point hover tooltips on an SVG sparkline are unreliable<\/strong> in HTML<br>Content (sanitizer strips <code>&lt;title><\/code>, z-index\/stacking issues block the<br>hover target). A whole-card <code>title=\"...\"<\/code> attribute works fine \u2014 don&#8217;t<br>chase per-point tooltips unless you have time to spend on it.<\/li>\n\n\n\n<li><strong>DAX string literals need doubled quotes<\/strong> (<code>\"\"<\/code>) for HTML attributes,<br>e.g. <code>style=\"\"color:red;\"\"<\/code>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">One-shot version (if you already know what you want)<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Build an HTML Content KPI card measure for [metric]: headline = full year<br>total to millions ($X.XM), badge = vs. prior year variance and %<br>(gray &#8216;no prior year&#8217; if only one year of data exists), background = last<br>12 months as an SVG sparkline, and a scrollable table underneath listing<br>each of those 12 months with formatted values, sticky header, thin<br>hover-only scrollbar.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">This single prompt reproduces the whole pattern in one pass, skipping the<br>incremental back-and-forth \u2014 useful once you&#8217;ve done it once and know the<br>shape you want.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Monthly-grain variant<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use this instead when the comparison should be month-over-month (latest<br>month vs. the month before it) rather than year-over-year \u2014 matching the<br>&#8220;left column&#8221; cards from the executive summary page.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;Build an HTML Content KPI card measure for [metric]: headline = latest<br>month&#8217;s total to millions ($X.XM), badge = vs. prior month variance and %<br>(color-coded green\/red, or gray &#8216;no prior month&#8217; if only one month of data<br>exists), background = last 12 months as an SVG sparkline, and a scrollable<br>table underneath listing each of those 12 months with formatted values,<br>sticky header, thin hover-only scrollbar.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The only structural difference from the yearly version: anchor on<br><code>DimDate[MonthPeriod]<\/code> (or your model&#8217;s month-key column) for both the<br>headline and the comparison, using <code>_LatestPeriod<\/code> \/ <code>_LatestPeriod - 1<\/code><br>instead of <code>DimDate[Year]<\/code> \/ <code>_SelectedYear - 1<\/code>. The background sparkline<br>and table stay the same either way since they were already monthly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Prompt Playbook: KPI Card with Background Trend + Scrollable Table (Power BI HTML Content visual, built via DAX) Use this [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[20,11],"tags":[],"class_list":["post-25","post","type-post","status-publish","format-standard","hentry","category-claude-ai","category-power-bi-tutorials"],"_links":{"self":[{"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/posts\/25","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/comments?post=25"}],"version-history":[{"count":1,"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/posts\/25\/revisions"}],"predecessor-version":[{"id":26,"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/posts\/25\/revisions\/26"}],"wp:attachment":[{"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/media?parent=25"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/categories?post=25"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.datascientist.ca\/blog\/wp-json\/wp\/v2\/tags?post=25"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}