JavaScriptTernary Operator

Ternary Operator

The conditional operator — condition ? a : b — is the only operator in JavaScript that takes three operands, which is why it's also called the ternary operator. It's a compact way to pick between two values based on a test, and the most common shortcut you'll write after if/else.

The shape

JS
const result = condition ? valueIfTrue : valueIfFalse;

The whole thing is an expression — it produces a value, so you can assign it, pass it as an argument, or interpolate it into a template literal. That's what makes it different from if/else, which is a statement and doesn't have a value.

JS
const age = 17;
const role = age >= 18 ? "adult" : "minor";

console.log(`You are a ${age >= 18 ? "n adult" : " minor"}.`);
// "You are a minor."

function fee(member) {
  return member ? 0 : 20;
}
Ternary vs if/else

Both can express the same logic, but they fit different shapes.

When ternary wins

JS
// Short, both branches produce a value, no side effects
const label = isAdmin ? "Admin" : "User";
const className = isActive ? "row active" : "row";
const greeting = `Hi, ${name || "friend"}`;

When if/else wins

JS
// Side effects, multiple statements, early returns
if (user.banned) {
  log("blocked", user.id);
  notifyOps(user);
  return;
}

// Multi-line branches read awfully as ternaries — don't.
A rough rule
If both branches are simple expressions that fit on one line each, ternary. If either branch needs more than that — side effects, multiple statements, early returns — use `if`/`else`.
Nesting (sparingly)

Ternaries can nest because each branch is itself an expression. They become hard to read fast.

Readable nested ternary

JS
const status =
  user.banned     ? "banned" :
  user.verified   ? "active" :
  /* otherwise */   "pending";

console.log(status);

The trick that makes this readable is the aligned layout: each condition on its own line, results aligned in a column, with the final fallback labeled. Read top to bottom, it works like a tiny lookup table.

Unreadable nested ternary

JS
const status = user.banned ? "banned" : user.verified ? "active" : user.invited ? "pending" : "none";
Three levels is the soft limit
Beyond two or three branches, an early-returning `if`/`else if` chain or a `switch` is almost always clearer. ESLint has `no-nested-ternary` if your team wants to enforce a hard line.
Common patterns

Pluralisation

JS
function items(n) {
  return `${n} item${n === 1 ? "" : "s"}`;
}

console.log(items(0)); // "0 items"
console.log(items(1)); // "1 item"
console.log(items(7)); // "7 items"

Default with a guard

JS
const heading = title ? title : "Untitled";
// Often simpler with || or ??:
const heading2 = title || "Untitled";
const heading3 = title ?? "Untitled";

Class name selection

JS
const className = [
  "btn",
  size === "lg" ? "btn-lg" : "btn-md",
  disabled ? "btn-disabled" : "",
].filter(Boolean).join(" ");

In JSX

JS
// {user
//   ? <p>Welcome, {user.name}</p>
//   : <p>Please sign in.</p>}
Pitfalls

Confusing precedence

JS
// Looks like "(a + 1) ? b : c"
const x = a + 1 ? b : c;       // works — + binds tighter than ?:

// But mixing assignment in branches can surprise you
const y = ok ? (a = 1) : (b = 1);   // assigns AND returns the value

Side effects in branches

JS
// Both branches evaluate?  No — only the chosen one.
const result = condition
  ? expensive()        // runs ONLY if condition is truthy
  : cheap();           // runs ONLY if condition is falsy

Ternaries short-circuit — only the chosen branch is evaluated. That's a feature, but it can hide work in a branch where you didn't expect it.

Ternary vs short-circuit (&&, ||, ??)

There's an overlap with the logical operators. A quick guide:

  • a ? a : b → use a || b (or a ?? b if 0/""/false are valid for a).

  • cond ? doThing() : null → use cond && doThing().

  • cond ? x : y where both x and y matter → keep the ternary.

JS
// Same effect — three ways
const userName  = name || "Guest";
const userName2 = name ?? "Guest";
const userName3 = name ? name : "Guest";

// Prefer the shortest one that's faithful to the intent
Style and formatting

Prettier and most other formatters wrap a ternary across three lines when it gets long:

JS
const message =
  err instanceof NetworkError
    ? "Check your connection and try again."
    : "Something went wrong, please reload.";

The question mark and colon align with the wrapped indentation, which makes the two branches visually distinct.

The "two-branch" test
Before you reach for a ternary, ask: do I have *exactly two* paths that each produce a value? If yes, ternary. If you find yourself wanting to log something on one branch, return early on the other, or chain a third case — that's an `if`/`else` (or a lookup object) in disguise.