Tips for dynamic styling in markdown visualizations

Omni’s markdown visualizations are incredibly flexible and powerful. You can reference query data and valuesand insert them directly in your markdown code. And if you’re comfortable writing it, you can use HTML and CSS to highly customize the presentation of your results.

I wanted to share a few tricks using calculations and mustache syntax that I’ve started using to make more dynamically styled markdown tiles with HTML/CSS. At the end, I also have a few reminders and tips.

Example 1: A simple text summary

A summary of a results table that shows an up/down arrow, different language/text and different coloring based on a trend direction.

Here’s what my results table looks like and a peek into one of my calculations:

In the calculation for Trend I display different text based on the value of the change calculation in the column next to it. I did something identical for the AIM Trend metric as well. These calculated columns are not meant to be shown in the final presentation. Instead, I’ve created them to use as css class names in my markdown code, like this:

<span class="trend arrow {{result._last.calc_1.value_static}}">

I can then write different CSS declarations to style however I want. I can even use pseudo-elements (like ::before) to insert content. Here’s the full CSS and HTML of my “smart summary” to see how I customize text like higher/lower and modify the arrow direction:

<style>
  .trend {
    --up-base-color: rgb(41, 139, 229);
    --down-base-color: rgb(255,133,21);
    --trend-base-color: var(--color-text4);
    color: var(--trend-base-color);
    font-weight: 500;
  }
  .trend.down {
    --trend-base-color: var(--down-base-color);
  } 
  .trend.up {
    --trend-base-color: var(--up-base-color);
  }
  .arrow::before {
    content: "\21E7";
    display: inline-flex;
    background-color: rgb(from var(--trend-base-color) r g b / 0.3);
    width: 20px;
    height: 20px;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    margin-right: 4px;    
  }
  .arrow.down::before {
    transform: rotate(180deg);
  }
  .arrow.flat::before {
    content: "\2014";
  }
  .metric1-text.up::after {
    content: "higher";
  }
  .text.down::after {
    content: "lower";
  }
  .aim-text.up::after {
    content: "opportunities";
  }
  .aim-text.down::after {
    content: "challenges";
  }
  .metric1-text.flat::after {
    content: "level";
  }
</style>
<h4>{{filters.users.traffic_source.value}} Performance Summary</h4>
<p>{{filters.users.traffic_source.value}} traffic is <span class="trend arrow {{result._last.calc_1.value_static}}">{{result._last.calc_1.value}} {{result._last.count_percent_change_from_previous_1.value}}</span> versus last year, driven by <span class="trend metric1-text {{result._last.calc_1.value_static}}"></span> demand in this segment. 
</p>
<p>
Despite this, AIM (An Important Metric) is <span class="trend arrow {{result._last.calc_2.value_static}}">{{result._last.calc_2.value}} {{result._last.total_sale_price_percent_change_from_previous_1.value}}</span>, with pricing showing potential <span class="trend aim-text {{result._last.calc_2.value_static}}"></span>.
</p>

Example 2: Highlight only specific rows in results

In this example, I combine the mustache iterator syntax with some css display properties to list off the dates where we exceeded a specific threshold:

Here’s the code:

<style>
  .hit {
    font-weight: bold;
  }
  .miss {
    display: none;
  }
</style>
In the {{filters.order_items.created_at.summary}}, 
we exceeded our target of {{result._first.calc_1.value}} 
on these days:
<ul>
{{#result}}
   <li class="{{calc_4.value_static}}">
      {{order_items.created_at[date].value}}
   </li>
{{/result}}
</ul>

Some tips

  1. The markdown editor has a little menu that you can use to pick common values:
  2. On your results table, you can right-click on a cell to grab the markdown reference for that specific value:
  3. When you want to use a markdown value in your css as class names, you don’t need it to “bring along” any additional capabilities, like drilling. To do this, make sure you reference values as .value_static - like this <li class="{{calc_4.value_static}}">
  4. I really am no excel-syntax wizard. I rely HEAVILY on our calculate-with-AI feature to generate what I need :robot: :tada:
  5. While fun to go crazy, there are some limitations in what can get rendered for downloads and printing, so make sure you test your creations out!

I’m sure there are a million other creative things you can do - or have already done! I’d love if other folks shared some examples and ideas here as well.

2 Likes