Skip to main content

Excel Data Bars in Interactive Report

Oracle APEX Tutorial

In-cell Progress Bars Excel-Style Data Bars inside Oracle APEX Interactive Reports

Two production-ready approaches to rendering beautiful progress bars directly inside Interactive Report columns — no plugins, no external libraries. One uses APEX's native Percent Graph column type; the other uses fully custom HTML expressions with traffic-light color coding. Both cover all three columns: Salary, Performance, and Experience.

📊 Salary Progress Bar
🟢 Performance Color Coding
Experience Tracker
🎨 Traffic Light Colors
🚫 Zero Plugins
Pure SQL + HTML
Solution 01
Percent Graph Column
Native APEX built-in — zero HTML needed
Solution 02
Custom HTML Expression
Full control — traffic-light color logic
The Story
How this started
I was staring at a plain Interactive Report showing salary, performance scores, and years of experience as just numbers in a column. Completely fine functionally, but a manager walked by, glanced at the screen and said "can you make it look like Excel data bars?" — and that one comment sent me down a two-hour rabbit hole.
I tried the obvious thing first…
My first instinct was to use an APEX chart inside the report. I tried embedding a sparkline — that was way overkill for what was essentially just a "fill a rectangle" requirement. Then I found the Percent Graph column type buried in the column settings — I had never noticed it before. It worked instantly for the salary bar, but the moment I tried to colour-code performance (green/amber/red based on thresholds), I hit a hard wall: the Percent Graph type gives you zero colour control.
Finally this approach worked…
I switched to the HTML Expression field in column formatting and injected the bar width directly as a CSS width percentage driven by hidden SQL columns. The trick was computing hex color strings right inside the SQL CASE expression, then substituting them via #COLUMN_NAME# tokens. No JavaScript, no Dynamic Actions — just a clean SQL query and a few lines of HTML per column.
💡 Both solutions work purely in the SQL query and column settings. No JavaScript, no Dynamic Actions, no CSS regions needed. Everything is driven by computed SQL columns.
Live Preview
Interactive Report — All 3 Progress Bars
Animated Demo
Salary
88%
₹92,000
Perf · High
82%
High
Perf · Mid
62%
Medium
Perf · Low
34%
Low
Experience
65%
13 yrs
Solution 01
1

Using the Percent Graph Column Type

The simplest approach. APEX has a native Percent Graph column type that renders a built-in horizontal progress bar directly in the Interactive Report cell. All you need is a SQL column with a value between 0 and 100 — APEX does the rest.

One issue I faced…
The Percent Graph label was confusing at first — I expected to find it under "Bar Chart" or something similar. It's actually under Column Formatting › Type, not under the Attributes tab. Took me a solid five minutes of clicking around before I spotted it.
SQL IR Source Query — Solution 1
SELECT
    e.EMP_ID,
    e.EMP_NAME,
    e.DEPARTMENT,
    e.JOB_TITLE,
    e.LOCATION,
    e.SALARY,
    e.PERFORMANCE,
    e.EXPERIENCE,
    e.STATUS,

    ROUND( (e.SALARY / MAX(e.SALARY) OVER()) * 100 )
        AS SALARY_PCT,

    ROUND( e.PERFORMANCE )
        AS PERF_PCT,

    ROUND( LEAST( (e.EXPERIENCE / 20) * 100, 100 ) )
        AS EXP_PCT

FROM EMPLOYEE_DATA e
ORDER BY e.DEPARTMENT, e.EMP_ID

After adding the SQL, set the column type for each computed column in Page Designer:

Column Type: Percent Graph
SALARY_PCT Column Type Percent Graph — renders a bar proportional to max salary in the result set
PERF_PCT Column Type Percent Graph — performance score already on 0–100 scale
EXP_PCT Column Type Percent Graph — experience capped at 20 years = 100%
Page Designer IR Region Columns SALARY_PCT / PERF_PCT / EXP_PCT Column Formatting → Type = Percent Graph
⚠️ Limitation: The Percent Graph type uses APEX's default bar colour with no per-row colour control. If you need traffic-light colouring (green / amber / red), jump straight to Solution 2.
Solution 02
2

Using Custom HTML Expressions

The powerful approach. You write raw HTML in the Column Formatting → HTML Expression field, using #COLUMN_NAME# substitution tokens to inject SQL values. This gives you complete control over bar width, colour, labels, and layout — for all three columns.

I tried X but it didn't work…
My first attempt at the HTML expression used a <meter> HTML element. It rendered, but the styling was completely browser-controlled and inconsistent across Chrome and Firefox. The second attempt used CSS clip-path — that just disappeared entirely in APEX's report rendering. Settled on a plain position:absolute filled div inside a relative container — dead simple, works everywhere.
SQL IR Source Query — Solution 2
SELECT
    e.EMP_ID,
    e.EMP_NAME,
    e.DEPARTMENT,
    e.JOB_TITLE,
    e.SALARY,
    e.PERFORMANCE,
    e.EXPERIENCE,
    e.HIRE_DATE,
    e.LOCATION,
    e.STATUS,

    ROUND( (e.SALARY / MAX(e.SALARY) OVER()) * 100 )
        AS SAL_PCT,

    ROUND( e.PERFORMANCE )
        AS PERF_PCT,

    ROUND( LEAST(e.EXPERIENCE / 20 * 100, 100) )
        AS EXP_PCT,

    CASE
        WHEN e.PERFORMANCE >= 75 THEN '#43a047'
        WHEN e.PERFORMANCE >= 50 THEN '#fb8c00'
        ELSE                           '#e53935'
    END AS PERF_COLOR,

    CASE
        WHEN ROUND((e.SALARY / MAX(e.SALARY) OVER())*100) >= 70
            THEN '#1a73e8'
        WHEN ROUND((e.SALARY / MAX(e.SALARY) OVER())*100) >= 40
            THEN '#7b61ff'
        ELSE
            '#1a73e8'
    END AS SAL_COLOR,

    '#6d28d9' AS EXP_COLOR

FROM EMPLOYEE_DATA e

Configure the three visible columns as Plain Text, then set the HTML Expression for each one:

Column Type: Plain Text (SALARY, PERFORMANCE, EXPERIENCE)
SALARY PERFORMANCE EXPERIENCE
Column Appearance Column Formatting → HTML Expression
HTML Expression Column: SALARY
<div style="display:flex;align-items:center;gap:6px;width:100%">
  <div style="flex:1;height:18px;background:#dce8f8;border-radius:3px;
             overflow:hidden;position:relative">
    <div style="position:absolute;left:0;top:0;height:100%;
               border-radius:3px;width:#SAL_PCT#%;
               background:#SAL_COLOR#"></div>
  </div>
  <span style="font-size:11px;font-weight:600;color:#0C447C;
              min-width:58px;text-align:right">
    ₹#SALARY#
  </span>
</div>
Uses #SAL_PCT# for bar width and #SAL_COLOR# for fill colour — both computed in SQL
HTML Expression Column: PERFORMANCE
<div style="display:flex;align-items:center;gap:6px;width:100%">
  <div style="flex:1;height:18px;background:#e8f5e9;border-radius:3px;
             overflow:hidden;position:relative">
    <div style="position:absolute;left:0;top:0;height:100%;
               border-radius:3px;width:#PERF_PCT#%;
               background:#PERF_COLOR#"></div>
  </div>
  <span style="font-size:11px;font-weight:600;color:#1b5e20;
              min-width:36px;text-align:right">
    #PERFORMANCE#%
  </span>
</div>
Green / Amber / Red bar driven by #PERF_COLOR# from the CASE expression in SQL
HTML Expression Column: EXPERIENCE
<div style="display:flex;align-items:center;gap:6px;width:100%">
  <div style="flex:1;height:18px;background:#ede7f6;border-radius:3px;
             overflow:hidden;position:relative">
    <div style="position:absolute;left:0;top:0;height:100%;
               border-radius:3px;width:#EXP_PCT#%;
               background:#EXP_COLOR#"></div>
  </div>
  <span style="font-size:11px;font-weight:600;color:#4a148c;
              min-width:44px;text-align:right">
    #EXPERIENCE# yrs
  </span>
</div>
Uses #EXP_PCT# (capped at 100% via LEAST) and #EXP_COLOR# for the purple fill

Set all helper columns to Hidden so they remain available as substitution tokens without appearing as visible columns:

Column Type: Hidden (helper columns)
SAL_PCT PERF_PCT EXP_PCT PERF_COLOR SAL_COLOR EXP_COLOR
Key Insight: Hidden columns are still rendered in the HTML output — they just aren't displayed as visible columns. This is what makes #SAL_PCT#, #PERF_COLOR#, and #EXP_COLOR# available inside HTML expressions of other columns.
Result Preview

What the Report Looks Like

Finally this approach worked…
When I hit Save and ran the page for the first time with all three columns set up, the bars appeared exactly as I had pictured them. The manager walked by again, looked at the screen, and said "now that looks like proper BI software."
Employee Data — Interactive Report · HTML Expression Result
Live Preview
EmployeeDeptSalaryPerformanceExperienceStatus
Ananya R.Engineering
88%
82%
75%
Active
Rajan M.Finance
55%
62%
40%
Active
Divya S.HR
34%
38%
20%
Inactive
Karthik P.Operations
100%
90%
100%
Active
How it all works
🧮
Analytic MAX() for relative scaling
MAX(e.SALARY) OVER() returns the maximum salary across the whole result set without grouping. Dividing each salary by this max and multiplying by 100 gives a percentage relative to the top earner.
🔢
LEAST() caps Experience at 100%
LEAST(experience/20*100, 100) treats 20 years as the ceiling. Anyone with 20+ years still shows as 100% — preventing bars from overflowing their container.
🚦
CASE outputs CSS color strings
A SQL CASE expression outputs a hex colour string like '#43a047' based on the numeric threshold. This is injected directly into the HTML as a CSS background value via the #PERF_COLOR# token.
🔤
#TOKEN# substitution at render time
APEX replaces #COLUMN_NAME# tokens in HTML Expression fields with the row value before the HTML reaches the browser. Hidden columns are still substituted even though they aren't visible.
👁️
Hidden vs Plain Text columns
Helper columns (PCT values, color strings) are set to Hidden. The three display columns — Salary, Performance, Experience — are Plain Text with an HTML Expression override.
📐
Flexbox keeps label + bar aligned
The HTML expression uses a display:flex wrapper. The bar track gets flex:1 to fill the cell width, and a fixed min-width label sits right-aligned beside it — keeping all rows consistent.
Solution Comparison — Percent Graph vs HTML Expression
FeatureSolution 1 — Percent GraphSolution 2 — HTML Expression
Setup complexity Very simple~ Moderate
Salary column bar Yes Yes + ₹ symbol
Performance column bar Yes Yes + traffic-light color
Experience column bar Yes Yes + "yrs" label
Custom bar color per row Not supported Full control via CASE
Traffic-light coloring Not supported Green / Amber / Red
Currency / unit symbol Not supported Any symbol
Works with IR search/filter Yes Yes

Quick Setup Checklist

Add the SQL query with computed SAL_PCT, PERF_PCT, EXP_PCT and color columns to your Interactive Report source
Set SALARY, PERFORMANCE, EXPERIENCE column type to Plain Text
Paste the HTML Expression for each of the three display columns under Column Formatting → HTML Expression
Set helper columns SAL_PCT, PERF_PCT, EXP_PCT, PERF_COLOR, SAL_COLOR, EXP_COLOR to Hidden
Run and preview — all three bars render instantly with no additional CSS or JavaScript
Optionally tune the CASE thresholds (75/50 for performance, 70/40 for salary, 20-year cap for experience) to match your business rules

Comments

Popular posts from this blog

Screen Recorder in Oracle APEX (Single Page)

Oracle APEX Tutorial Screen Recorder in Oracle APEX : Single Page Build a fully functional browser-based screen recorder inside Oracle APEX using just one Static Content region and native JavaScript. No plugins, no external libraries, no server uploads required. ✍️ Why I Built This I was working on a client project where the support team needed to record screen issues and share them directly from the APEX application, without switching to any external tool. Installing third-party software was not an option on their machines, and every screen recorder extension required IT approval. That is when I thought: the browser already has everything we need. Why not build it right inside APEX? That idea turned into this. &#127916; Start / Stop Recording &#128065; Instant Preview ⬇️ One-click Download &#128266; Audio + Video ...

Freeze panes in Interactive Grid : Driven by a page item

Oracle APEX Tutorial Freeze Panes in Interactive Grid : Driven by a Page Item Lock N columns in place with a select list : no plugins, no hacks. Pure JavaScript, a Dynamic Action, and clean CSS that survives sort, search, and pagination. Live Demo GitHub Code Create page item Add page JavaScript Dynamic Action Optional CSS 1 Create the P1_FREEZE_COLS select list In Page Designer, add a Select List page item. Configure it as shown below. Also set the Interactive Grid region's Static ID to emp_grid via Properties → Advanced → Static ID . Name P1_FREEZE_COLS List of Values Static Values : Display/Return 0 through 5 Default Value 0 Template Optional / Floating Label Region Static ID emp_grid 2 Page JavaScript : Execute when Page Loads Paste t...

Excel-Style Keyboard Shortcuts in Interactive Grid

Oracle APEX Tutorial Excel-Style Keyboard Shortcuts in Interactive Grid Add Alt+A , Alt+D , Alt+S and Alt+R to your editable IG : no plugins, just four clean setup steps using APEX's built-in actions registry. Alt + A   Add Row Alt + D   Delete Row Alt + S   Save Alt + R   Refresh Alt + Shift + F1   View All Shortcuts Live Demo GitHub Code Editable IG Static ID Cursor Focus JS Init Code Testing 1 Prerequisites : Make your IG Editable ⚠️ Keyboard shortcuts only work on an Editable Interactive Grid . The row-add-row , row-delete , and save actions only exist in the IG's action registry when the grid is in editable mode. If you skip this, actions.lookup() will return null and throw an error. In your Interactive Grid region's attributes, set Edit → Enabled to...