Tested on: Excel 365 v2509 · Excel 2021 · Excel 2019 · last verified 2026-06-05
TL;DR — The If...Then...Else statement runs different code depending on whether a condition is True. Copy this skeleton and adapt it:
Sub GradeScore()
Dim score As Long
score = Range("A1").Value
If score >= 90 Then
Range("B1").Value = "A"
ElseIf score >= 75 Then
Range("B1").Value = "B"
ElseIf score >= 60 Then
Range("B1").Value = "C"
Else
Range("B1").Value = "Fail"
End If
End Sub
That single block is 90% of everything you'll ever do with conditions in VBA. The rest of this guide shows the patterns that save you from the bugs everyone hits.
Why the If statement matters
Every macro that "decides" something — flag overdue invoices, color cells over budget, skip blank rows — is built on If. Get the structure right once and you stop writing the tangled, half-broken conditionals that make VBA painful to maintain.
The four shapes of If
| Shape | When to use | Needs End If? |
|---|---|---|
Single-line If |
One short action, no Else |
No |
Block If...End If |
One branch, multiple lines | Yes |
If...Else |
Two outcomes | Yes |
If...ElseIf...Else |
Three or more outcomes | Yes |
' Single-line — no End If, keep it to one statement
If cell.Value = 0 Then cell.Value = "n/a"
' Block — multiple lines need End If
If cell.Value = 0 Then
cell.Value = "n/a"
cell.Interior.Color = vbYellow
End If
Rule of thumb: the moment you need two actions or an
Else, switch to the block form withEnd If. Mixing single-line and block syntax is the #1 cause of "Block If without End If" compile errors.
Example 1 — Flag overdue invoices
Sub FlagOverdue()
Dim r As Range
For Each r In Range("D2:D200") ' D = due date
If r.Value < Date And r.Offset(0, 1).Value <> "Paid" Then
r.Offset(0, 2).Value = "OVERDUE"
r.Offset(0, 2).Interior.Color = RGB(255, 199, 206)
End If
Next r
End Sub
Two conditions joined with And — both must be true. The cell is overdue and not yet paid.
Example 2 — And vs Or, made obvious
And requires every condition to be true. Or needs only one. This trips up beginners constantly:
' Approve only if amount is small AND the requester is a manager
If amount <= 5000 And role = "Manager" Then status = "Auto-approved"
' Escalate if the amount is large OR the account is flagged
If amount > 50000 Or isFlagged = True Then status = "Needs review"
VBA does not short-circuit by default, so avoid calling a function inside the second condition that would error when the first is false — split it into nested Ifs instead.
Example 3 — Nested If for a real decision tree
Sub ShippingTier()
Dim weight As Double, country As String
weight = Range("A2").Value
country = Range("B2").Value
If country = "US" Then
If weight <= 1 Then
Range("C2").Value = "Standard $5"
Else
Range("C2").Value = "Heavy $12"
End If
Else
Range("C2").Value = "International $25"
End If
End Sub
Nesting is fine two levels deep. Beyond that, readability collapses — that's your signal to switch to Select Case (see below).
Example 4 — IIf for quick inline assignments
For a simple two-way choice, the IIf function fits on one line:
Range("C2").Value = IIf(Range("A2").Value > 0, "Profit", "Loss")
Warning: IIf evaluates both the true and false arguments, even the one it discards. Never put a divide-by-zero or a risky function call inside it.
Example 5 — Test a cell, not just a variable
Sub HighlightBlanks()
Dim r As Range
For Each r In Range("A2:A500")
If IsEmpty(r) Then
r.Interior.Color = vbRed
ElseIf Not IsNumeric(r.Value) Then
r.Interior.Color = vbYellow
End If
Next r
End Sub
IsEmpty, IsNumeric, and IsError are the guards that keep your If from crashing on messy data.
Example 6 — Exit early to avoid deep nesting
Sub ProcessRow(r As Range)
If r.Value = "" Then Exit Sub ' guard clause — bail out fast
If Not IsNumeric(r.Value) Then Exit Sub
r.Offset(0, 1).Value = r.Value * 1.2
End Sub
Guard clauses flatten your code. Instead of wrapping everything in If valid Then ... End If, reject the bad cases up front and let the main logic run unindented.
When to use If vs Select Case
| Situation | Use |
|---|---|
| 1–2 outcomes, or conditions on different variables | If...Else |
| 3+ outcomes testing the same variable | Select Case |
| Ranges of values (1–10, 11–20…) | Select Case ... To |
Combining And/Or across variables |
If...ElseIf |
If you find yourself writing ElseIf x = 1 ... ElseIf x = 2 ... ElseIf x = 3 against one variable, Select Case is cleaner and faster to read.
Common errors (and the fix)
"Block If without End If" — You opened a multi-line If but never closed it, or you put code after Then on the same line and added more lines. Each block If needs exactly one End If.
"Else without If" — Usually a stray End If above the Else, or a single-line If followed by an orphan Else. Re-indent the block; the mismatch becomes obvious.
The condition is always true/false — You wrote = (comparison) where you meant assignment, or compared a string to a number. Use Debug.Print on the condition to see what VBA actually evaluates.
Text comparison fails unexpectedly — "paid" = "Paid" is False. Wrap both sides in LCase() for case-insensitive matches, or set Option Compare Text at the top of the module.
Stop hand-writing conditionals — describe the rule instead
Conditional logic is exactly where VBA gets brittle: one nested If too many and nobody can safely change it six months later. ExcelMaster Agent lets you write the rule in plain English — "flag rows in column D where the due date has passed and status isn't Paid, and color them red" — and it generates and runs the equivalent Python/Excel logic for you, no End If to forget. Try it free →
Related guides
- VBA For Loop in Excel — 8 Real-World Examples
- VBA Select Case — A Complete Guide with Examples
- VBA While Loop — While, Do While & Do Until Explained
FAQ
Can I use If Then Else on one line?
Yes, but only for a single action with no Else spanning multiple lines: If x > 0 Then y = 1. Add an Else or a second statement and you must use the block form with End If.
How many ElseIf branches can I have?
As many as you need — but if all branches test the same variable, Select Case is the more readable choice past three.
Why does my If condition always run?
Most often a type mismatch (comparing text to a number) or a case-sensitivity issue ("Yes" <> "yes"). Print the condition with Debug.Print to confirm what VBA sees.
What's the difference between If and IIf?
If is a statement that controls which lines run. IIf() is a function that returns one of two values — and it evaluates both, so keep risky expressions out of it.
