Chaining Ternary Operators in JavaScript Tutorial

Learn how to chain multiple ternary operators in JavaScript for multi-way value selection. Covers formatting rules, readability guidelines, when chaining is appropriate, and safer alternatives.

JavaScriptbeginner
9 min read

The basic ternary operator handles two-way decisions: true or false, one value or the other. But what about three-way or four-way decisions? What if you need to return "A" for scores above 90, "B" for scores above 80, "C" for scores above 70, and "F" for everything else? Chaining ternary operators lets you express multi-way value selection in a single expression, similar to an else if chain but in expression form.

Chained ternaries are controversial. Used well with proper formatting, they are concise and elegant. Used poorly, they become the least readable code in your entire codebase. This tutorial teaches you the correct syntax, formatting rules that keep chained ternaries readable, practical use cases where they genuinely help, and the clear signals that tell you to use if else or a lookup object instead.

Chaining Syntax

A chained ternary places another ternary expression in the "false" branch of the previous one:

javascriptjavascript
// Single ternary (2 outcomes)
condition ? valueA : valueB
 
// Chained ternary (3 outcomes)
condition1 ? valueA
  : condition2 ? valueB
  : valueC
 
// Chained ternary (4 outcomes)
condition1 ? valueA
  : condition2 ? valueB
  : condition3 ? valueC
  : valueD

Each : introduces a new branch. The last value (without a condition) acts as the default, similar to the else block in an if else chain:

javascriptjavascript
function getGrade(score) {
  return score >= 90 ? "A"
    : score >= 80 ? "B"
    : score >= 70 ? "C"
    : score >= 60 ? "D"
    : "F";
}
 
console.log(getGrade(95)); // "A"
console.log(getGrade(82)); // "B"
console.log(getGrade(55)); // "F"

How JavaScript Evaluates Chained Ternaries

The ternary operator is right-associative, meaning it groups from right to left. This is what makes chaining work naturally:

javascriptjavascript
// This expression:
a ? "A" : b ? "B" : "C"
 
// Is evaluated as:
a ? "A" : (b ? "B" : "C")
 
// NOT as:
(a ? "A" : b) ? "B" : "C"  // This would be wrong

JavaScript evaluates from left to right at runtime:

  1. Check a. If true, return "A" and stop.
  2. Check b. If true, return "B" and stop.
  3. If neither matched, return "C".

This mirrors how else if chains evaluate: top to bottom, first match wins.

Formatting Rules for Readability

The difference between a readable chained ternary and an unreadable one is formatting. Follow these rules:

Rule 1: One Condition Per Line

javascriptjavascript
// BAD: all on one line
const tier = points >= 1000 ? "gold" : points >= 500 ? "silver" : points >= 100 ? "bronze" : "basic";
 
// GOOD: each condition on its own line
const tier = points >= 1000 ? "gold"
  : points >= 500 ? "silver"
  : points >= 100 ? "bronze"
  : "basic";

Rule 2: Align the Colons

javascriptjavascript
// GOOD: colons align vertically, creating a visual pattern
const label = status === "active"   ? "Online"
            : status === "idle"     ? "Away"
            : status === "offline"  ? "Offline"
            : "Unknown";
 
// ALSO GOOD: indent-style alignment
const label = status === "active" ? "Online"
  : status === "idle" ? "Away"
  : status === "offline" ? "Offline"
  : "Unknown";

Rule 3: Maximum Three to Four Conditions

Chain LengthReadabilityRecommendation
2 conditionsGoodSingle-line or two-line ternary
3 conditionsAcceptableMulti-line with formatting
4 conditionsAt the limitConsider if else or lookup
5+ conditionsPoorUse if else, switch, or lookup object
Stop at Four Conditions

If your chained ternary needs five or more conditions, it is too complex for an inline expression. Switch to an if else chain, a switch statement, or an object lookup. Readable code is always worth a few extra lines.

Practical Chained Ternary Examples

HTTP Status Categories

javascriptjavascript
function getStatusCategory(code) {
  return code >= 500 ? "server-error"
    : code >= 400 ? "client-error"
    : code >= 300 ? "redirect"
    : code >= 200 ? "success"
    : "informational";
}
 
console.log(getStatusCategory(200)); // "success"
console.log(getStatusCategory(404)); // "client-error"
console.log(getStatusCategory(503)); // "server-error"

Dynamic Badge Colors

javascriptjavascript
function getBadgeColor(priority) {
  return priority === "critical" ? "#dc2626"
    : priority === "high" ? "#ea580c"
    : priority === "medium" ? "#ca8a04"
    : "#16a34a"; // low or default
}
 
const style = { backgroundColor: getBadgeColor(ticket.priority) };

Conditional Text in Templates

javascriptjavascript
function formatTimeAgo(minutes) {
  return minutes < 1 ? "just now"
    : minutes < 60 ? `${Math.floor(minutes)} min ago`
    : minutes < 1440 ? `${Math.floor(minutes / 60)} hr ago`
    : `${Math.floor(minutes / 1440)} days ago`;
}
 
console.log(formatTimeAgo(0.5));  // "just now"
console.log(formatTimeAgo(25));   // "25 min ago"
console.log(formatTimeAgo(180));  // "3 hr ago"
console.log(formatTimeAgo(4320)); // "3 days ago"

Clamping Values to Ranges

javascriptjavascript
function clampToRange(value, min, max) {
  return value < min ? min
    : value > max ? max
    : value;
}
 
console.log(clampToRange(5, 1, 10));   // 5
console.log(clampToRange(-3, 1, 10));  // 1
console.log(clampToRange(15, 1, 10));  // 10

Chained Ternary vs If Else vs Switch

The same grading logic expressed three ways:

javascriptjavascript
// Chained ternary (1 expression, compact)
const grade = score >= 90 ? "A"
  : score >= 80 ? "B"
  : score >= 70 ? "C"
  : "F";
 
// If else chain (multi-statement, explicit)
let grade;
if (score >= 90) {
  grade = "A";
} else if (score >= 80) {
  grade = "B";
} else if (score >= 70) {
  grade = "C";
} else {
  grade = "F";
}
 
// Early return (cleanest in a function)
function getGrade(score) {
  if (score >= 90) return "A";
  if (score >= 80) return "B";
  if (score >= 70) return "C";
  return "F";
}
ApproachLinesconst-compatibleBest for
Chained ternary4YesInline assignments, pure value selection
If else chain10No (needs let)Complex logic, side effects
Early return5N/A (returns directly)Functions that map input to output

When Not to Chain Ternaries

When Branches Have Side Effects

javascriptjavascript
// BAD: side effects in ternary branches
const result = isValid
  ? (logSuccess(), sendEmail(), "success")
  : (logFailure(), showAlert(), "failure");
 
// GOOD: use if else for side effects
if (isValid) {
  logSuccess();
  sendEmail();
  result = "success";
} else {
  logFailure();
  showAlert();
  result = "failure";
}

When Conditions Are Complex

javascriptjavascript
// BAD: complex conditions in a chain
const access = user.isAdmin && !user.isSuspended ? "full"
  : user.role === "editor" && resource.type === "article" ? "edit"
  : user.isPremium || user.hasTrial ? "read"
  : "none";
 
// GOOD: name the conditions, use if else
const hasFullAccess = user.isAdmin && !user.isSuspended;
const canEdit = user.role === "editor" && resource.type === "article";
const canRead = user.isPremium || user.hasTrial;
 
if (hasFullAccess) return "full";
if (canEdit) return "edit";
if (canRead) return "read";
return "none";

When There Are Five or More Branches

javascriptjavascript
// BAD: too many levels
const day = n === 0 ? "Sunday"
  : n === 1 ? "Monday"
  : n === 2 ? "Tuesday"
  : n === 3 ? "Wednesday"
  : n === 4 ? "Thursday"
  : n === 5 ? "Friday"
  : n === 6 ? "Saturday"
  : "Invalid";
 
// GOOD: use an array or object lookup
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const day = days[n] ?? "Invalid";

Best Practices

Chained Ternary Guidelines

Follow these rules to keep chained ternaries readable and maintainable.

Format with one condition per line. Never write a chained ternary on a single line. Each ? value : pair should have its own line, with colons aligned.

Limit to three or four conditions. Beyond four conditions, readability drops sharply. Use if else, switch, or an object lookup for longer chains.

Use only for pure value selection. Chained ternaries should select a value, not execute logic. If any branch has side effects, logging, or multiple statements, use if else.

Keep conditions simple. Each condition in the chain should be a single comparison or a named boolean. Complex multi-part conditions obscure the chain's structure.

Consider an object lookup first. When mapping exact values (strings, numbers) to results, an object is almost always shorter and clearer than a chained ternary. Reserve chaining for range-based conditions where lookups do not work.

Common Mistakes and How to Avoid Them

Chaining Pitfalls

These mistakes turn chained ternaries into maintenance nightmares.

Writing everything on one line. A five-condition chain on a single line is unreadable. Always break chained ternaries across lines.

Putting the chain in the true branch instead of the false branch. The standard pattern chains in the false branch: condition1 ? value1 : condition2 ? value2 : default. Chaining in the true branch (condition1 ? (condition2 ? value1 : value2) : value3) creates nested parenthetical logic that is much harder to follow.

Missing the default value. Every chained ternary should end with a default value (no condition on the last branch). Without it, the last branch requires a condition, and there is no fallback for unmatched inputs.

Using chained ternaries where a lookup works. If every condition is x === "value", replace the entire chain with an object: const result = map[x] ?? "default". Objects are more extensible and easier to read.

Next Steps

Master loops for repetitive tasks

With conditionals covered, learn how for loops and while loops let you repeat operations across data collections.

Combine ternaries with array methods

Use ternary expressions inside .map(), .filter(), and .reduce() callbacks for concise data transformations.

Practice refactoring if else to ternary

Take existing functions with simple if else assignments and rewrite them as ternary expressions. Then decide which version reads better.

Learn object destructuring for cleaner code

Combine ternary results with destructuring patterns for concise variable assignments from complex data structures.

Rune AI

Rune AI

Key Insights

  • Chain in the false branch: the standard pattern is condition1 ? value1 : condition2 ? value2 : default
  • One condition per line: never write chained ternaries on a single line; formatting determines readability
  • Four conditions maximum: beyond four branches, switch to if else, switch, or object lookup
  • Pure value selection only: chained ternaries should return values, not execute side effects or complex logic
RunePowered by Rune AI

Frequently Asked Questions

How many ternary operators can I chain together?

JavaScript has no syntactic limit on chaining depth. However, readability is the practical limit. Three to four conditions in a chain is manageable with proper formatting. Five or more conditions should use if else, switch, or an object lookup instead. The goal is code that a teammate can understand in seconds, not code that is as short as possible.

Are chained ternary operators bad practice?

Not inherently. A well-formatted chained ternary with three conditions for pure value selection is perfectly readable. Chained ternaries become bad practice when they are on one line, have complex conditions, include side effects, or chain beyond four levels. The formatting and use case determine whether the pattern is clean or messy.

How does JavaScript evaluate chained ternaries?

The ternary operator is right-associative: `a ? x : b ? y : z` groups as `a ? x : (b ? y : z)`. At runtime, evaluation is left-to-right: check `a` first, then `b`, then fall through to `z`. This matches the mental model of an else if chain reading top to bottom.

Can I mix ternary operators with other operators?

Yes, but use parentheses for clarity. The ternary operator has low precedence (just above assignment), so most arithmetic and [comparison operator](/tutorials/programming-languages/javascript/js-operators-arithmetic-logical-and-comparison) evaluate before it. In complex expressions like `total + isExpress ? 10 : 5`, the `+` binds more tightly than expected. Write `total + (isExpress ? 10 : 5)` to make intent clear.

Should I use chained ternaries or switch statements?

For exact value matching (comparing a variable to specific strings or numbers), use a switch statement or object lookup. For range-based conditions (greater than, less than), a chained ternary can be more concise than if else when there are only three to four branches. Use whichever approach communicates intent most clearly to your team.

Conclusion

Chained ternary operators let you express multi-way value selection in a single expression, replacing short else if chains when the goal is assigning or returning one of several values. The key discipline is formatting: one condition per line, aligned colons, and a maximum of three to four conditions. Beyond that threshold, if else chains, switch statements, or object lookups are always more readable.