cancel
Showing results forĀ 
Search instead forĀ 
Did you mean:Ā 
Technical Blog
Explore in-depth articles, tutorials, and insights on data analytics and machine learning in the Databricks Technical Blog. Stay updated on industry trends, best practices, and advanced techniques.
cancel
Showing results forĀ 
Search instead forĀ 
Did you mean:Ā 
pstyld
Databricks Employee
Databricks Employee

Organizations use AI/BI dashboard tables to review accounts, catch problems, and decide what to do next. Yet a plain table can hold all the right data and still be hard to read.

One way to improve the end user experience is to render HTML directly inside a table. AI/BI dashboard tables support an HTML display type, allowing an HTML string to render as something more visual and useful than plain text.

In this post, you'll build five reusable Unity Catalog functions that turn ordinary table values into:

  • Status badges - for quickly flagging specific conditions, like account health
  • Utilization bars - for visually comparing values, like active versus licensed users
  • Trend indicators - for highlighting changes, like increases and decreases over time
  • AI-prioritized action cards - for surfacing important information, like accounts that need attention
  • Action links - for connecting table data to external systems or workflows

In this blog we will build each pattern separately so you can see how it works in an AI/BI dashboard table. At the end, we'll bring all five together into a single table to see how these small enhancements can transform a traditional plain table.

We will build the following consumer-friendly table visual in AI/BI Dashboards using your Unity Catalog table:

final_build.png

Feel free to follow along using Databricks Free Edition!

How we will be implementing the HTML in a table visualization

Here are three main ideas we use in this post:

  • HTML display type in a table - Every column in an AI/BI Dashboard table has a display style type. The default is Basic (plain text). Switch it to HTML and the dashboard renders the cell's string as markup. Simply requires a column to contain an HTML string.
  • Unity Catalog Functions - We will create functions that return a STRING of HTML in a column. The function decides how something looks, and the query that calls it decides what the data means and which values map to which colors.
  • Reusable and governed - Because the functions live in Unity Catalog, other queries, dashboards, and teams can reuse them without copying HTML into every query.

Before you start

A few things to keep in mind:

  • This walkthrough uses a small, fictional five-row sample so each pattern is easy to see.
  • For the demo, every query below is added as a dataset inside the dashboard. These are ordinary SQL queries, so you can run them just as easily in the SQL editor or a notebook, or save them as views. The dashboard is simply a convenient place to see the HTML render.
  • AI/BI Dashboards take an HTML string and render the HTML output. Content is run through an HTML sanitizer before rendering. When dynamically generating HTML, also consider where the underlying data comes from. For user input or untrusted values, additional validation or escaping may be appropriate.

Step 1: Create the data and the Unity Catalog functions

  1. Open the SQL Editor or a Notebook.
  2. In the code below, change your default catalog (YOUR_CATALOG) to a development catalog you can write to, then run the script below once in the SQL editor or a notebook. The catalog name is the only line you should need to edit.
    USE CATALOG YOUR_CATALOG;
    CREATE SCHEMA IF NOT EXISTS html_tables;
    USE SCHEMA html_tables;
    
    -- -----------------------------------------------------------------------------
    -- Sample data: one row per customer account (small demo dataset)
    -- -----------------------------------------------------------------------------
    CREATE OR REPLACE TABLE customer_accounts (
      account_id                STRING,
      account_name              STRING,
      account_owner             STRING,
      annual_contract_value     DECIMAL(12,2),
      renewal_date              DATE,
      health_status             STRING,
      renewal_risk              STRING,
      implementation_progress   INT,
      active_users              INT,
      licensed_users            INT,
      monthly_usage_change_pct  DOUBLE,
      open_support_cases        INT,
      ai_summary                STRING,
      recommended_action        STRING,
      crm_record_url            STRING
    );
    
    INSERT INTO customer_accounts VALUES
      ('ACC-1001', 'Northstar Retail',       'Maya Patel',     420000.00, DATE'2026-10-15', 'Healthy',         'Low',    92, 1840, 2000,  18.4, 1,
       'Adoption is strong across all purchased products. Usage increased this month, and executive engagement remains high.',
       'Identify expansion opportunities and begin the renewal conversation.',
       'https://example.com/crm/accounts/ACC-1001'),
      ('ACC-1002', 'Blue River Financial',   'Jordan Lee',     680000.00, DATE'2026-08-30', 'At Risk',         'High',   48,  620, 1500, -21.7, 7,
       'Usage has declined for two consecutive months. Several support cases remain unresolved.',
       'Schedule an executive risk review and create a support recovery plan.',
       'https://example.com/crm/accounts/ACC-1002'),
      ('ACC-1003', 'Summit Health Partners', 'Sofia Martinez', 310000.00, DATE'2027-01-20', 'Needs Attention', 'Medium', 67,  790, 1200,  -4.2, 3,
       'Implementation is progressing, but product adoption and user growth have slowed.',
       'Review the remaining implementation milestones with the customer.',
       'https://example.com/crm/accounts/ACC-1003'),
      ('ACC-1004', 'Apex Manufacturing',     'Ethan Brooks',   275000.00, DATE'2026-12-05', 'Healthy',         'Low',    84,  940, 1000,  12.9, 0,
       'Implementation is nearly complete and usage continues to grow.',
       'Prepare an adoption success story for the next business review.',
       'https://example.com/crm/accounts/ACC-1004'),
      ('ACC-1005', 'Greenline Energy',       'Noah Williams',  350000.00, DATE'2026-09-18', 'Needs Attention', 'High',   73,  410,  900, -12.6, 4,
       'Adoption is concentrated in a small user group and the renewal date is approaching.',
       'Create a product adoption plan and confirm renewal stakeholders.',
       'https://example.com/crm/accounts/ACC-1005');
    
    -- -----------------------------------------------------------------------------
    -- 1. html_badge(): a colored pill for a categorical status
    -- -----------------------------------------------------------------------------
    CREATE OR REPLACE FUNCTION html_badge(
      label STRING,
      background_color STRING,
      text_color STRING
    )
    RETURNS STRING
    COMMENT 'Creates a colored pill-style HTML badge. Arguments: label = text to display; background_color = hex color for the badge, such as #2574B5; text_color = hex color for the text, typically #FFFFFF.'
    RETURN CONCAT(
      '<span style="display:inline-block;',
        'background:', background_color, ';',
        'color:', text_color, ';',
        'padding:4px 10px;',
        'border-radius:12px;',
        'font-weight:600;">',
        label,
      '</span>'
    );
    
    -- -----------------------------------------------------------------------------
    -- 2. html_utilization(): a value pair with a color-coded progress bar
    -- -----------------------------------------------------------------------------
    CREATE OR REPLACE FUNCTION html_utilization(
      numerator DOUBLE,
      denominator DOUBLE,
      label STRING
    )
    RETURNS STRING
    COMMENT 'Creates an HTML utilization metric with a progress bar. Arguments: numerator = current or used value; denominator = total or available value; label = text displayed after the percentage. Utilization above 75% is green, 30-75% is yellow, and below 30% is red.'
    RETURN CONCAT(
      '<div style="min-width:140px;">',
        '<strong>',
          FORMAT_NUMBER(numerator, 0),
          ' / ',
          FORMAT_NUMBER(denominator, 0),
        '</strong>',
        '<br>',
        '<span style="font-size:12px;color:#5E7077;">',
          ROUND(numerator / NULLIF(denominator, 0) * 100, 1),
          '% ', label,
        '</span>',
        '<div style="background:#E1E3E2;',
        'height:6px;',
        'border-radius:3px;',
        'margin-top:5px;">',
          '<div style="background:',
            CASE
              WHEN numerator / NULLIF(denominator, 0) * 100 > 75 THEN '#02A36F'
              WHEN numerator / NULLIF(denominator, 0) * 100 >= 30 THEN '#F8A805'
              ELSE '#FE3722'
            END,
          ';width:',
            LEAST(
              GREATEST(numerator / NULLIF(denominator, 0) * 100, 0),
              100
            ),
          '%;',
          'height:6px;',
          'border-radius:3px;">',
          '</div>',
        '</div>',
      '</div>'
    );
    
    -- -----------------------------------------------------------------------------
    -- 3. html_trend(): a directional arrow for a positive/negative change
    -- -----------------------------------------------------------------------------
    CREATE OR REPLACE FUNCTION html_trend(
      value DOUBLE
    )
    RETURNS STRING
    COMMENT 'Creates an HTML trend indicator. Arguments: value = positive or negative percentage change. Positive values display a green up arrow, negative values display a red down arrow, and zero displays a neutral value.'
    RETURN CASE
      WHEN value > 0 THEN CONCAT(
        '<span style="color:#02A36F;font-weight:600;">',
        'ā–² ', FORMAT_NUMBER(value, 1), '%',
        '</span>'
      )
      WHEN value < 0 THEN CONCAT(
        '<span style="color:#FE3722;font-weight:600;">',
        'ā–¼ ', FORMAT_NUMBER(ABS(value), 1), '%',
        '</span>'
      )
      ELSE
        '<span style="color:#5E7077;font-weight:600;">ā— 0.0%</span>'
    END;
    
    -- -----------------------------------------------------------------------------
    -- 4. html_action_card(): a priority-colored card for a recommended action
    -- -----------------------------------------------------------------------------
    CREATE OR REPLACE FUNCTION html_action_card(
      action STRING,
      priority STRING
    )
    RETURNS STRING
    COMMENT 'Creates an HTML action card. Arguments: action = recommended action text; priority = High, Medium, or Low. High displays red, Medium yellow, and Low green.'
    RETURN CONCAT(
      '<div style="',
      'background:#F8F9FC;',
      'border-left:4px solid ',
        CASE priority
          WHEN 'High' THEN '#FE3722'
          WHEN 'Medium' THEN '#F8A805'
          WHEN 'Low' THEN '#02A36F'
          ELSE '#2574B5'
        END,
      ';padding:8px 10px;',
      'max-width:320px;white-space:normal;overflow-wrap:break-word;">',
        '<div style="font-size:11px;font-weight:700;',
        'text-transform:uppercase;margin-bottom:4px;color:',
          CASE priority
            WHEN 'High' THEN '#FE3722'
            WHEN 'Medium' THEN '#F8A805'
            WHEN 'Low' THEN '#02A36F'
            ELSE '#2574B5'
          END,
        ';">',
          priority, ' Priority',
        '</div>',
        '<strong>Next Action</strong>',
        '<br>',
        action,
      '</div>'
    );
    
    -- -----------------------------------------------------------------------------
    -- 5. html_link(): a styled, clickable hyperlink
    -- -----------------------------------------------------------------------------
    CREATE OR REPLACE FUNCTION html_link(
      label STRING,
      url STRING
    )
    RETURNS STRING
    COMMENT 'Creates a styled HTML hyperlink. Arguments: label = clickable text displayed to the user; url = destination URL that opens when selected. Link color defaults to #2574B5.'
    RETURN CONCAT(
      '<a href="', url, '" target="_blank" ',
      'style="color:#2574B5;font-weight:600;">',
      label, ' ↗',
      '</a>'
    );
    
  3. The code creates:
    1. An html_tables schema in your specified catalog, 
    2. A customer_accounts sample table
    3. Five Unity Catalog functions. Each function returns a STRING of HTML. We won't go deep on the HTML or UC functions here, but if you want to understand any of them, ask Genie Code to walk you through a function line by line!

Step 2: Create and name your dashboard

  1. In the main navigation bar, select Dashboards.
  2. Click Create dashboard.
  3. Rename the dashboard to something descriptive, such as FirstName-LastInitial - HTML Table Demo.
  4. At the top right, select a Serverless SQL Warehouse.

Let's build the table visualization with each function one pattern at a time.

For each build you:

  • Create a small dataset with the Unity Catalog functions from above.
  • Then add a Table visualization and switch the column's display type to HTML.

 

Build 1: Color-coded status badges

Turn the plain health_status value into a pill-style badge. The function draws the pill and the query decides the color based on the value.

Create the dataset in AI/BI Dashboards

  1. In the dashboard, open the Data tab.
  2. Select Add SQL dataset.
  3. Select your catalog and the html_tables schema.
  4. Paste the query below and run it. View the results. Notice the HTML in the status_badge column created by the html_badge() function.
  5. Rename the dataset to health_status_badges.
SELECT
  account_name,
  health_status,
  html_badge(
    health_status,
    CASE health_status
      WHEN 'Healthy' THEN '#02A36F'
      WHEN 'Needs Attention' THEN '#F8A805'
      WHEN 'At Risk' THEN '#FE3722'
      ELSE '#2574B5'
    END,
    CASE health_status
      WHEN 'Needs Attention' THEN '#1C3037'
      ELSE '#FFFFFF'
    END
  ) AS status_badge
FROM customer_accounts

Add the table visualization

  1. Open the dashboard canvas.
  2. Add a Visualization.
  3. Choose Table.
  4. From health_status_badges, add the following columns: 
    1. account_name
    2. health_status
    3. status_badge.
  5. Select the status_badge column in the configuration panel > Style > change Display type to HTML.
  6. Optionally hide the original health_status column.

build_1_html_badge.png

Here the CASE expressions in the html_badge() function carry the business logic:

  • Healthy is green.
  • Needs Attention is amber (with dark text so the label stays readable).
  • At Risk is red.
  • Swap the colors in the query and the badge changes. The function never has to.

Build 2: License utilization

Combine active_users and licensed_users into a single compact metric with a color-coded progress bar.

Create the dataset

  1. Open the Data tab and select Add SQL dataset.
  2. Select your catalog and the html_tables schema.
  3. Paste the query below and run it. View the results. Notice the HTML in the license_utilization column created by the html_utilization() function.
  4. Rename the dataset to license_utilization.
SELECT
  account_name,
  active_users,
  licensed_users,
  html_utilization(active_users, licensed_users, 'active') AS license_utilization
FROM customer_accounts

Add the table visualization 

  1. Add a Table visualization to the canvas
  2. From license_utilization, add the following columns:
    1. account_name, 
    2. active_users, 
    3. licensed_users,
    4. license_utilization
  3. Select the license_utilization column in the configuration panel > Style > set Display type to HTML.
  4. Optionally hide the raw active_users and licensed_users columns.

build_1.png

The function computes active divided by licensed and colors the bar automatically: above 75% green, 30 to 75% amber, below 30% red.

Build 3: Usage trends

Turn a plain percentage change into a directional arrow.

Create the dataset

  1. Open the Data tab and select Add SQL dataset.
  2. Select your catalog and the html_tables schema.
  3. Paste the query below and run it. View the results. Notice the HTML in the usage_trend column created by the html_trend() function.
  4. Rename the dataset to usage_trends.
SELECT
  account_name,
  monthly_usage_change_pct,
  html_trend(monthly_usage_change_pct) AS usage_trend
FROM customer_accounts

Add the table visualization

  1. Add a Table visualization to the canvas.
  2. From usage_trends, add the following columns:
    1. account_name, 
    2. monthly_usage_change_pct,
    3. usage_trend
  3. Select the usage_trend column in the configuration panel > Style > set Display type to HTML.
  4. Optionally hide the original monthly_usage_change_pct column.

build_3_usage.png

Positive values render a green up arrow, negative values a red down arrow, and zero a neutral dot.

Build 4: AI-prioritized action cards

This build combines an AI function (ai_classify) with a reusable HTML function. 

The flow is: recommended action, then an AI-generated priority, then an HTML card.

Create the dataset

  1. Open the Data tab and select Add SQL dataset.
  2. Select your catalog and the html_tables schema.
  3. Paste the query below and run it. View the results. Notice the HTML in the next_action column created by the html_action_card() function.
  4. Rename the dataset to prioritized_actions.
WITH actions AS (
  SELECT
    account_name,
    recommended_action,
    ai_classify(recommended_action, ARRAY('High', 'Medium', 'Low')) AS action_priority
  FROM customer_accounts
)
SELECT
  account_name,
  recommended_action,
  action_priority,
  html_action_card(recommended_action, action_priority) AS next_action
FROM actions

Add the table visualization

  1. Add a Table visualization to the canvas.
  2. From prioritized_actions, add the following columns:
    1. account_name, 
    2. recommended_action, 
    3. action_priority,
    4. next_action
  3. Select the next_action column in the configuration panel > Style > set Display type to HTML.
  4. Optionally show action_priority while you validate the AI output, then hide it from the final table.

build_4_next_actions.png

Here ai_classify() reads each recommended_action and returns one of High, Medium, or Low, and html_action_card() renders that priority as a colored card. Using a fixed label set keeps the output aligned with the card's colors.

A note on AI output: AI classification can vary, so always check the result and build this accordingly.

Build 5: Action links

Finish by turning the CRM URL into a clickable action. This is what makes the table more than a report: users can move straight from an insight to the system where they take the next step.

Create the dataset

  1. Open the Data tab and select Add SQL dataset.
  2. Select your catalog and the html_tables schema.
  3. Paste the query below and run it. View the results. Notice the HTML in the crm_link column created by the html_link() function.
  4. Rename the dataset to crm_actions.
SELECT
  account_name,
  crm_record_url,
  html_link('Open CRM', crm_record_url) AS crm_link
FROM customer_accounts

Add the table visualization

  1. Add a Table visualization to the canvas.
  2. From  crm_actions, add the following columns: 
    1. account_name, 
    2. crm_record_url,
    3. crm_link
  3. Select the crm_link column in the configuration panel > Style > set Display type to HTML.
  4. Optionally hide the raw crm_record_url column.

build_5_crm_action.png

The sample URLs use example.com as placeholders. In a real dashboard, this could point to Salesforce, ServiceNow, Jira, an internal app, or any other operational system.

Bring It All Together

You've built and tested each HTML pattern separately. Now let's combine them into a single dataset to see how they work together.

Create the dataset

  1. Open the Data tab and select Add SQL dataset.
  2. Select your catalog and the html_tables schema.
  3. Paste the query below and run it. View the results.
  4. Rename the dataset to final_table.
WITH actions AS (
  SELECT
    *,
    ai_classify(
      recommended_action,
      ARRAY('High', 'Medium', 'Low')
    ) AS action_priority
  FROM customer_accounts
)

SELECT
  account_name AS Account,

  html_badge(
    health_status,
    CASE health_status
      WHEN 'Healthy' THEN '#02A36F'
      WHEN 'Needs Attention' THEN '#F8A805'
      WHEN 'At Risk' THEN '#FE3722'
      ELSE '#2574B5'
    END,
    CASE
      WHEN health_status = 'Needs Attention' THEN '#1C3037'
      ELSE '#FFFFFF'
    END
  ) AS Health,

  html_utilization(
    active_users,
    licensed_users,
    'active'
  ) AS `License Utilization`,

  html_trend(
    monthly_usage_change_pct
  ) AS `Usage Trend`,

  html_action_card(
    recommended_action,
    action_priority
  ) AS `Next Action`,

  html_link(
    'Open CRM',
    crm_record_url
  ) AS CRM
FROM actions;

Add the table visualization

  1. Add a Table visualization to the canvas.
  2. From  final_table, add the following columns:
    1. Account, 
    2. CRM,
    3. Health,
    4. License Utilization,
    5. Next Action,
    6. Usage Trend
  3. For all columns except Account, open Style > set Display type to HTML.

final_build.png

Use Genie Code!

None of these Unity Catalog functions to return HTML were written from scratch. 

Genie Code helped build them. You describe what you want in plain language, and it writes, explains, and refines the code for you. That is also how you should create and improve them. You can:

  • Add a new state, change the colors, or adjust the values of the provided functions.
  • Create a brand new HTML function for a new pattern this post did not cover.

Made something better? Share your function and a screenshot in the comments. The best ideas help everyone!

Learn more

New to AI/BI Dashboards? The AI/BI for Data Analysts course on Databricks Academy covers building interactive dashboards, creating visualizations, using Genie Code for AI development, publishing, scheduling, and more.

 

2 Comments