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

# Markdown visualizations

> Build custom Markdown visualizations in Omni that combine text, images, links, iframes, and live query data in a single tile.

Markdown visualizations allow for a combination of Markdown elements and query variables. You can use it to create a visualization that includes text, images, links, data, iframes, and more.

## Creating Markdown with AI

You can use the [Query Helper](/ai/queries) to generate markdown visualizations based on natural language prompts. The AI will create rich, flexible data displays that combine HTML, CSS, Mustache template variables, and [custom Omni components](#adding-visual-components) like `<Sparkline>` and `<ChangeArrow>`.

To create a Markdown visualization with AI:

<Steps>
  <Step>
    Create a query in a workbook.
  </Step>

  <Step>
    Open the Query Helper.
  </Step>

  <Step>
    Ask Blobby to create a custom layout (e.g., "Create a custom HTML layout for this data" or "Show this as a formatted text display with sparklines")
  </Step>

  <Step>
    Review and refine the generated Markdown visualization as needed.
  </Step>
</Steps>

Once generated, you can continue to refine the visualization through the chat or manually edit it using the Markdown editor. To learn more about building visualizations with AI, refer to [Generating visualizations with AI](/ai/visualizations).

## Using the Markdown editor

When you select **Markdown** as the visualization type, a Markdown editor will display in the chart's **Options** pane. As changes are made, the chart area will automatically update.

At the top of the editor is a toolbar to help you generate correct [Markdown syntax](https://www.Markdownguide.org/cheat-sheet/) for common formatting actions.

<img src="https://mintcdn.com/omni-e7402367/5sjkphTfeROO5Xkh/visualize-present/visualizations/types/markdown-editor.png?fit=max&auto=format&n=5sjkphTfeROO5Xkh&q=85&s=fa09623f205269a76c30559328aeb29c" alt="The Markdown editor in the Options pane with a formatting toolbar at the top" width="2282" height="1604" data-path="visualize-present/visualizations/types/markdown-editor.png" />

You can also access the Markdown editor in a draft dashboard by clicking the <Icon icon="ellipsis-vertical" iconType="solid" /> icon on a Markdown tile and selecting **Edit in chart**. The tile will update as you make changes in the editor.

<img src="https://mintcdn.com/omni-e7402367/2r2MgtOOlGAFh_OX/visualize-present/visualizations/types/dashboard-markdown-editor.png?fit=max&auto=format&n=2r2MgtOOlGAFh_OX&q=85&s=79eb4e13cd1c06134c9a2716f43373f2" alt="Editing a Markdown tile from a draft dashboard using the Edit in chart option" width="2558" height="1306" data-path="visualize-present/visualizations/types/dashboard-markdown-editor.png" />

### Including HTML

The Markdown editor interprets Markdown first and foremost. While it is possible to incorporate HTML, it helps to think of these more as text documents than true HTML files.

When formatting your code, keep the following in mind:

* **Indentation is interpreted as a code block**. Keep your code flush to the left to prevent unintended code blocks.
* **Empty lines may cause odd behavior**. In Markdown, these are paragraph indicators. This occurs because the `div` is included in a code block as plain text, which will strand its closing tag.

<Note>
  Omni sanitizes your HTML and CSS to prevent potential security vulnerabilities. This includes removing JavaScript and interactive elements such as `<form>`, `<input>`, and `<script>`.

  When an element is removed for security reasons, a message will appear in the Markdown: *“This element is considered dangerous and will not be rendered.”*
</Note>

#### Best practices

While you can use HTML, try to use it sparingly to simplify things. If you do need to use HTML elements:

* **Use supported semantic HTML elements where possible**, such as `article` or `section`. Large numbers of `divs` in a row can cause parsing issues.
* **Limit the depth of `div` nesting**. Deeply nested elements increase the likelihood of conflicts between the Markdown and HTML parsing.
* **Use `<style></style>` and CSS classes** over inline `style` tags for custom CSS.

#### Limitations

* **PDFs in deliveries and downloads may render differently than what's visible in a browser,**, including:
  * **Directly referencing native HTML tags** - for example, `h3 { font-size: 18px; }` may not always work
  * **Some characters in CSS can't be parsed** causing those style declarations to be ignored, including:
    * The quotation marks needed for `content: "<value>";` will not work
    * `&.` and `&:` notation in your CSS will be ignored. Do not use this syntax if you nest your CSS.
* **Invalid HTML or CSS syntax may not render correctly in PNGs or PDFs** even if it correctly renders in a browser. For example, `@media`

### Dark mode styling

When your Omni instance is in dark mode, the Markdown visualization automatically receives a `prefers-dark` class. You can use this class to apply different styles based on the theme.

To target elements in dark mode, use the `&.prefers-dark` selector in your CSS:

```css theme={null}
<style>
  h1 {
    color: red;
  }

  .custom-element {
    background: green;
  }

  &.prefers-dark h1 {
    color: blue;
  }

  &.prefers-dark .custom-element {
    background: yellow;
  }
</style>
```

In this example, `h1` elements will be red in light mode and blue in dark mode. The `custom-element` class will have a green background in light mode and yellow in dark mode.

## Referencing query elements

Data and other elements from the query can be exposed using [Mustache syntax](https://mustache.github.io/). For example, `{{query_element}}`. The full list of query elements can be seen using [`{{ inspect }}`](/visualize-present/mustache-reference#query-and-user-attribute-inspection).

To reference query elements, you can do any of the following:

<Steps>
  <Step>
    Use the **Query details** dropdown menu inside the Markdown editor.
  </Step>

  <Step>
    Click any cell in the results table to copy the Markdown syntax:

    <img src="https://mintcdn.com/omni-e7402367/5sjkphTfeROO5Xkh/visualize-present/visualizations/types/markdown_right_click.png?fit=max&auto=format&n=5sjkphTfeROO5Xkh&q=85&s=043d5c13b48aa72f4fbc05a3ad563900" alt="Right-clicking a cell in the results table to copy the Markdown syntax" width="666" height="468" data-path="visualize-present/visualizations/types/markdown_right_click.png" />
  </Step>

  <Step>
    Write the syntax directly, for example:

    ```handlebars theme={null}
    # Example field reference
    {{fields.blob_sales_view.total_sales_field.label}}

    # Example filter reference
    {{filters.blob_sales_view.total_sales_field.value}}
    ```
  </Step>
</Steps>

Refer to the [Markdown Mustache syntax reference](/visualize-present/mustache-reference) for more information and examples.

### Looping through the results set

To iteratively generate Markdown tiles based on the results set, use `{{#result}}` and `{{/result}}` to create a loop. For example:

```html wrap theme={null}
{{#result}} // start a loop
{{<view_name>.<field_name>.value}} // access contents of that loop  [...]
{{<view_name_n>.<field_name_n>.value}} // reference more fields  
(<br>) // // maybe add a newline to create sections
{{/result}} // end loop
```

Check out these examples to see this pattern in action:

* [Repeating pie charts](/showcase/visualizations/repeating-pie-chart)
* [Repeating square fill charts](/showcase/visualizations/repeating-square-fill-chart)
* [Repeating waffle charts](/showcase/visualizations/repeating-waffle-chart)

## Adding visual components

Along with adding images and code to help highlight your data, you can also use the built-in components to create inline visualizations:

* [**Change arrow**](#change-arrow) - Adds an arrow icon indicating the type of change between two data points
* [**Sparkline**](#sparkline) - Adds a [sparkline](https://en.wikipedia.org/wiki/Sparkline). Useful for seeing the shape in variation in a condensed way.

More complex visualizations are possible - check out the [Markdown examples gallery](/showcase) for inspiration.

### Change arrow

Adds an arrow icon indicating the type of change between two data points. If the change is a positive number, the arrow will be green. If negative, it will be red.

To use this component, your results must include two data points that can be used to calculate a change.

<img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/changearrow-01bd0a61c8b69da2e2986f69e7348790.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=8d1b05fd10a7a51f89a1641b67949263" alt="A ChangeArrow component displaying a green upward arrow between two data points" width="1598" height="848" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/changearrow-01bd0a61c8b69da2e2986f69e7348790.png" />

```html wrap theme={null}
<ChangeArrow current="{{result.0.users.count.value_static}}" comparison="{{result.1.users.count.value_static}}"></ChangeArrow>
```

#### Properties

| Name       | Value                                        | Notes                                                                                          |
| ---------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| current    | `result.0.view_name.field_name.value_static` | Use `value_static` instead of `value`, since the value and not the drillable element is needed |
| comparison | `result.1.view_name.field_name.value_static` |                                                                                                |

### Sparkline

Adds a [sparkline](https://en.wikipedia.org/wiki/Sparkline). Useful for seeing the shape in variation in a condensed way.

To use this component, your results must have more than one row of data and a field name.

<img src="https://mintcdn.com/omni-e7402367/aZ84MHc8H0bDix_i/images/docs/visualization-and-dashboards/visualization-types/assets/images/sparkline-b3ceb1cb4ad22f498f79a7097a31dd8d.png?fit=max&auto=format&n=aZ84MHc8H0bDix_i&q=85&s=ce786344187e2362dc64e32b22748b1f" alt="A Sparkline component displaying a small line chart inline with text" width="1708" height="1170" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/sparkline-b3ceb1cb4ad22f498f79a7097a31dd8d.png" />

```html theme={null}
<Sparkline field="users.count" color="cornflowerblue"></Sparkline>
```

#### Properties

| Name    | Value                           | Notes                       |
| ------- | ------------------------------- | --------------------------- |
| color   | CSS color, ex: `cornflowerblue` |                             |
| field   | `view_name.field_name`          |                             |
| height  | Integer, ex: `4`                |                             |
| width   | Integer, ex: `4`                |                             |
| reverse | `true`                          | Remove property for `false` |
| type    | `line` (default) or `bar`       |                             |

## Adding iframes

Using iframes in a Markdown visualization is also supported. iframes can be parameterized with [query elements](#referencing-query-elements).

By default, Omni applies restrictions ([sandboxing](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#:~:text=to%20insecure%20origins.-,sandbox,-Controls%20the%20restrictions)) when rendering iframes. This means that some website features, such as popups, may be unavailable or incompatible.

Use the dropdowns to check out some examples.

<Accordion title="Google Docs">
  <Note>
    Before embedding in Omni, publish the doc and retrieve its embed link.
  </Note>

  **Code**:

  ```html wrap theme={null}
  <iframe width="650" height="450" src="https://docs.google.com/document/d/id"></iframe>
  ```

  **Result**:

  <img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_google_docs-ed20043589abfaaf7f42469203df3079.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=8ddaaf35697cb5cdefe716c1c9fc81e5" alt="A Google Doc embedded in a Markdown visualization using an iframe" width="1538" height="870" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_google_docs-ed20043589abfaaf7f42469203df3079.png" />
</Accordion>

<Accordion title="Google News">
  **Code**:

  ```html theme={null}
  <iframe width="200" src="https://google.com/search?igu=1&q={{result._first.customers.name.value_static}}+company&tbm=nws&source=lnms&sa=X&ved=2ahUKEwjv1rPg7LmAAxXsFFkFHWTbCYcQ0pQJegQIPxAB&biw=1420&bih=840&dpr=2"></iframe>
  ```

  **Result**:

  <img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_google_news-ac5ad1e4e539c8f2e1594ff8c7dafbec.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=969a369c8b923cd3d2b4635878213099" alt="Google News search results embedded in a Markdown visualization using an iframe" width="1340" height="810" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_google_news-ac5ad1e4e539c8f2e1594ff8c7dafbec.png" />
</Accordion>

<Accordion title="Google Maps">
  **Code**:

  ```html theme={null}
  <iframe src="https://www.google.com/maps/embed/v1/search?q={{result.0.products.brand.value_static}}+in+{{result._first.users.city.value_static}},{{result._first.users.state.value_static}}&key=AIzaSyCXfF4zpXaYkgVaBzj3oZUtmcDAxpdoOGk&" width="100%" height="100%"></iframe>
  ```

  **Result**:

  <img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_map-9a292d13572087b641813818c9c4f446.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=fa38bb65a8620d501c8093d048233c96" alt="A Google Maps embed in a Markdown visualization using an iframe" width="1350" height="818" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_map-9a292d13572087b641813818c9c4f446.png" />
</Accordion>

<Accordion title="Twitter/X">
  **Code**:

  ```html theme={null}
  <iframe height=250 width=550 src="https://twitframe.com/show?url=https%3A%2F%2Ftwitter.com%2Fjack%2Fstatus%2F20"></iframe>
  ```

  **Result**:

  <img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_twitter-e69f51d1ea2ac91e76ff5e56ec2f8ecf.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=c57345821201456bdaf5f9adc5ae307c" alt="A tweet embedded in a Markdown visualization using an iframe" width="1344" height="820" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_twitter-e69f51d1ea2ac91e76ff5e56ec2f8ecf.png" />
</Accordion>

<Accordion title="Windy">
  **Code**:

  ```html theme={null}
  <iframe width="650" height="450" src="https://embed.windy.com/embed2.html?lat=39.018&lon=-77.539&detailLat=39.018&detailLon=-77.539&width=650&height=450&zoom=5&level=surface&overlay=wind&product=ecmwf&menu=&message=&marker=&calendar=now&pressure=&type=map&location=coordinates&detail=&metricWind=default&metricTemp=default&radarRange=-1"></iframe>
  ```

  **Result**:

  <img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_weather-a4c60ada8f58c44ac90c821c9e3a94d6.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=3401b0b12610335e381697d3cac1ef9f" alt="A Windy weather map embedded in a Markdown visualization using an iframe" width="1524" height="1146" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_weather-a4c60ada8f58c44ac90c821c9e3a94d6.png" />
</Accordion>

<Accordion title="YouTube">
  **Code**:

  ```html theme={null}
  <iframe width="560" height="315" src="https://www.youtube.com/embed/lNAzOJrV-Zk" title="YouTube video player"></iframe>
  ```

  **Result**:

  <img src="https://mintcdn.com/omni-e7402367/K4oAdi8TCvG1dpiF/images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_youtube-cfa2c9207a23e456cbf319160eacfd82.png?fit=max&auto=format&n=K4oAdi8TCvG1dpiF&q=85&s=5dad7107b1392b59e5f56f90dab9f93d" alt="A YouTube video embedded in a Markdown visualization using an iframe" width="1344" height="812" data-path="images/docs/visualization-and-dashboards/visualization-types/assets/images/iframe_youtube-cfa2c9207a23e456cbf319160eacfd82.png" />
</Accordion>

## Example gallery

Check out the [Markdown examples gallery](/showcase) to get inspired!
