Conditional formatting in Retool tables uses {{ currentRow.fieldName }} expressions in the column Inspector's Background color and Text color fields. Set colors with ternary expressions like {{ currentRow.status === 'overdue' ? '#fee2e2' : 'transparent' }}. For status badges, use the Tag column type which maps values to colored labels automatically.
| Fact | Value |
|---|---|
| Tool | Retool |
| Difficulty | Intermediate |
| Time required | 15-20 min |
| Compatibility | Retool Cloud and Self-hosted |
| Last updated | March 2026 |
Make Your Retool Tables Communicate Status at a Glance
A plain table with rows of black text forces users to read every cell to understand the data's health. Conditional formatting lets colors do the work — red rows for overdue items, green badges for completed tasks, yellow highlights for items needing attention.
Retool's Table component supports conditional formatting through the column Inspector's color fields. Every column has Background color and Text color properties that accept {{ }} expressions using the currentRow context variable, which gives you access to every field in the current row being rendered.
This tutorial covers three formatting approaches: per-cell colors using ternary expressions, the Tag column type for status badges, and row-level coloring that highlights entire rows based on a condition.
Prerequisites
- A Retool app with a Table component connected to a query
- The query returns at least one column suitable for status or numeric thresholds (e.g., status, amount, date)
- Basic familiarity with JavaScript ternary expressions
Step-by-step guide
Open the column Inspector for conditional formatting
Click on the Table component to select it. In the Inspector panel, scroll to the Columns section. Click the pencil icon next to the column you want to format — for example, a 'status' column. A column detail panel opens. Scroll down to find the 'Background color' and 'Text color' fields under the 'Formatting' or 'Styles' section. These fields accept either a static hex color string or a {{ }} Retool expression.
Expected result: Column detail panel is open showing Background color and Text color fields.
Apply a background color based on a status field
In the Background color field, enter a ternary expression using {{ currentRow.status }}. The currentRow variable is a special context object available inside Table column expressions — it gives you access to every field in the current row being rendered. Use a ternary expression to return different hex colors for different status values. For the Text color field, set a contrasting color so text remains readable against the background.
1// Background color field — for a 'status' column2{{ currentRow.status === 'active' ? '#d1fae5'3 : currentRow.status === 'pending' ? '#fef3c7'4 : currentRow.status === 'overdue' ? '#fee2e2'5 : 'transparent' }}67// Text color field — keeps text readable on colored backgrounds8{{ currentRow.status === 'active' ? '#065f46'9 : currentRow.status === 'pending' ? '#92400e'10 : currentRow.status === 'overdue' ? '#991b1b'11 : 'inherit' }}Expected result: Table cells in the status column display different background colors based on the status value.
Use the Tag column type for automatic status badges
For status columns, the Tag column type is often better than manual color expressions. Click the column's Type dropdown and select 'Tag'. A Tag Mapping section appears below. Click '+ Add tag' to map each status value to a color. For example: 'active' → Green, 'pending' → Yellow, 'overdue' → Red, 'completed' → Blue. The table automatically renders each cell as a colored rounded badge pill. Tag column type is ideal for low-cardinality status fields.
Expected result: Status cells display as colored badge pills with mapped colors from the Tag Mapping configuration.
Apply numeric threshold coloring
For numeric columns like 'days_overdue' or 'balance', apply colors based on thresholds rather than exact values. Use JavaScript comparison operators in the background color expression. This creates a traffic-light effect where the color intensity changes based on how far the value is from the threshold.
1// Background color for a 'days_overdue' numeric column2{{ currentRow.days_overdue > 30 ? '#fca5a5'3 : currentRow.days_overdue > 14 ? '#fcd34d'4 : currentRow.days_overdue > 0 ? '#fef3c7'5 : 'transparent' }}67// Background color for a 'utilization_pct' column8{{ currentRow.utilization_pct >= 90 ? '#fee2e2'9 : currentRow.utilization_pct >= 75 ? '#fef3c7'10 : '#d1fae5' }}Expected result: Numeric column cells display graduated colors based on value thresholds.
Apply formatting to entire rows using Row background color
To highlight entire rows (not just individual cells), find the 'Row color' or 'Row background color' setting in the Table Inspector's General section. This accepts the same {{ currentRow.xxx }} expression syntax and applies the color across every cell in the matching row. Row-level coloring is useful for highlighting selected rows, flagging rows that meet a critical condition, or alternating row colors by index.
1// Row background color — in the Table's General section2// Highlight rows where any column meets a critical threshold3{{ currentRow.priority === 'critical' ? '#fee2e2'4 : currentRow.is_flagged ? '#fef3c7'5 : 'transparent' }}67// Alternating row colors (zebra striping)8{{ currentRow._index % 2 === 0 ? '#f9fafb' : 'transparent' }}Expected result: Entire rows display background colors matching the conditional expression.
Combine formatting with cell-level custom content
For the most control, use a Custom column type instead of Background color expressions. In Custom column type, the Cell content field accepts HTML-like {{ }} expressions. You can render a colored span element with inline styles, an SVG icon, or any custom markup. This is more powerful than the Background color field because you control the entire cell content, not just its color.
1// Custom column type — Cell content field2// Renders a colored dot + text for the status3<div style="display: flex; align-items: center; gap: 6px;">4 <span style="5 width: 8px;6 height: 8px;7 border-radius: 50%;8 background: {{ currentRow.status === 'active' ? '#10b981' : currentRow.status === 'overdue' ? '#ef4444' : '#f59e0b' }};9 "></span>10 <span>{{ currentRow.status }}</span>11</div>Expected result: Status cells display a colored dot indicator followed by the status text.
Complete working example
1// This transformer is for reference only — shows the logic2// behind conditional formatting decisions.3// In practice, these expressions go directly into the column4// Inspector fields using {{ currentRow.xxx }} syntax.56// Priority-based background colors7const priorityBg = (priority) => ({8 critical: '#fee2e2',9 high: '#fef3c7',10 medium: '#eff6ff',11 low: 'transparent',12}[priority] || 'transparent');1314// Status badge color mapping15const statusBadge = (status) => ({16 active: { bg: '#d1fae5', text: '#065f46' },17 pending: { bg: '#fef3c7', text: '#92400e' },18 cancelled: { bg: '#f3f4f6', text: '#6b7280' },19 overdue: { bg: '#fee2e2', text: '#991b1b' },20}[status] || { bg: 'transparent', text: 'inherit' });2122// Numeric threshold coloring23const thresholdColor = (value, warn, crit) =>24 value >= crit ? '#fee2e2'25 : value >= warn ? '#fef3c7'26 : '#d1fae5';2728return data.map(row => ({29 ...row,30 _bg: priorityBg(row.priority),31 _statusStyle: statusBadge(row.status),32 _utilizationBg: thresholdColor(row.utilization, 75, 90),33}));Common mistakes
Why it's a problem: Using {{ row.fieldName }} instead of {{ currentRow.fieldName }} in column expressions
How to avoid: Inside Table column Inspector fields, the correct context variable is currentRow, not row. The variable row is not defined in this context and will cause an undefined error.
Why it's a problem: Setting a hard-coded white background (#ffffff) that breaks in dark mode
How to avoid: Use 'transparent' as the default/fallback background value. Retool's theme handles the base row color in both light and dark modes; you only need to override it when applying a semantic color.
Why it's a problem: Applying row-level colors AND cell-level colors and getting unexpected overrides
How to avoid: Cell-level Background color takes precedence over Row background color for that specific cell. If you need both, ensure your cell-level expression returns 'transparent' when the row-level color should show through.
Why it's a problem: Confusing conditional formatting (visual) with conditional logic (behavioral)
How to avoid: Conditional formatting only changes how data looks. It does not hide rows, change which data is fetched, or trigger actions. For behavioral conditions, use the Hidden property on components or SQL WHERE clauses.
Best practices
- Use 'transparent' as the fallback color value rather than a hard-coded color to stay compatible with dark mode themes
- Limit conditional coloring to 2-3 distinct states — too many colors create visual noise and lose their communicative value
- Prefer the Tag column type over manual Background color expressions for low-cardinality status fields — it's more maintainable
- Keep Background color expressions simple and self-documenting — if the expression is more than 3 conditions, move the logic to a Transformer
- Test conditional formatting in both light and dark theme modes to ensure readability
- Document your color conventions: use the same colors consistently (red=danger, yellow=warning, green=healthy) across all tables in your app
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Retool Table showing project tasks with columns: task_name, status (values: 'todo', 'in_progress', 'done', 'blocked'), due_date, and days_remaining (number). I need: (1) the 'status' column to use the Tag column type with appropriate color mappings, (2) the 'days_remaining' column to have a red background when < 0, yellow when 0-3, and green when > 3, (3) entire rows with status='blocked' to have a light red row background. Write the {{ currentRow.xxx }} expressions for each field in the Retool column Inspector.
Configure conditional formatting in a Retool Table for these columns: 'status' column using Tag type with mappings (active=green, pending=yellow, overdue=red, completed=blue), 'balance' column with background color {{ currentRow.balance < 0 ? '#fee2e2' : 'transparent' }}, and row background {{ currentRow.priority === 'critical' ? '#fee2e2' : 'transparent' }}. Show the Inspector configuration for each.
Frequently asked questions
Can I apply conditional formatting to a Retool table column based on values in a different column?
Yes — currentRow gives you access to all fields in the row, not just the column being formatted. You can set the background color of the 'amount' column based on {{ currentRow.status }}, or any other cross-column condition.
Why isn't my conditional formatting expression updating when the query re-runs?
Conditional formatting expressions are re-evaluated whenever the table's data changes. If the colors are stale, check that the query is running (look in the Debug Panel Queries tab) and that the column's Background color field actually has an expression referencing {{ currentRow.xxx }}. A static hex string like '#fee2e2' will never change — it must be a {{ }} expression.
Can I use conditional formatting on the selected row to highlight it differently?
The Table component has a built-in 'Selected row color' property in the Inspector that handles selected row highlighting. You do not need a conditional expression for this — set the highlight color directly in that field.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation