VBA Events: Macros That Run by Themselves (Worksheet_Change and More)

📎 This article includes 1 downloadable practice file ↓

⏱ 4 min read

So far every macro has needed a button or Alt+F8. Events are macros Excel runs for you when something happens: the file opens, a cell changes, the user switches sheet, the file is about to be saved. They’re how you build workbooks that feel like small applications — status columns that stamp the time when updated, codes that turn uppercase as you type, warnings before saving an incomplete sheet.

In this article
  1. Where event code lives
  2. Worksheet_Change: react to edits
  3. Auto-format what people type
  4. SelectionChange: highlight the active row
  5. Workbook events
  6. Useful events at a glance
  7. Where people go wrong
  8. Practice

Where event code lives

Not in a normal module. Event code goes in the module of the object that raises the event:

  • Sheet events — double-click the sheet (e.g. Sheet1 (Tasks)) in the VBA Project window.
  • Workbook events — double-click ThisWorkbook.

At the top of that code window, pick the object in the left drop-down (Worksheet or Workbook) and the event in the right one. VBA writes the correct first line for you — use that rather than typing it, because the exact name and arguments matter.

Worksheet_Change: react to edits

A task tracker: when someone changes the Status in column D, write the date and time in column E.

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim c As Range
    If Intersect(Target, Me.Range("D2:D1000")) Is Nothing Then Exit Sub

    Application.EnableEvents = False
    On Error GoTo Done
    For Each c In Intersect(Target, Me.Range("D2:D1000")).Cells
        If c.Value = "" Then
            c.Offset(0, 1).ClearContents
        Else
            c.Offset(0, 1).Value = Now
        End If
    Next c
Done:
    Application.EnableEvents = True
End Sub

Three details make this robust:

  • Target is every cell that changed — maybe one, maybe 500 pasted at once. Loop over it instead of assuming one cell.
  • Intersect limits the reaction to column D, so editing column A doesn’t stamp anything.
  • EnableEvents = False stops our own write to column E from triggering Worksheet_Change again.
⚠️ If the macro errors after EnableEvents = False and never turns it back on, every event in Excel stays off until you restart Excel. The On Error GoTo Done pattern above guarantees it is switched back on. If events ever “stop working”, run Application.EnableEvents = True in the Immediate window.

Auto-format what people type

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim c As Range
    If Intersect(Target, Me.Columns("B")) Is Nothing Then Exit Sub
    Application.EnableEvents = False
    For Each c In Intersect(Target, Me.Columns("B")).Cells
        If Not IsEmpty(c.Value) Then c.Value = UCase$(Trim$(c.Value))   ' GSTINs and codes in caps
    Next c
    Application.EnableEvents = True
End Sub

A sheet can only have one Worksheet_Change. If you need both behaviours, put both checks inside the same procedure.

SelectionChange: highlight the active row

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Me.Cells.Interior.ColorIndex = xlNone          ' clears all fill — use on sheets without other colours
    Target.EntireRow.Interior.Color = RGB(255, 247, 214)
End Sub

Handy for wide data, but it wipes existing cell colours. A gentler version uses conditional formatting with a formula that compares ROW() to a cell the macro updates.

Workbook events

' In ThisWorkbook
Private Sub Workbook_Open()
    Worksheets("Dashboard").Activate
    Worksheets("Dashboard").Range("B1").Value = "Opened " & Format(Now, "dd-mmm-yyyy hh:nn")
End Sub

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If Application.WorksheetFunction.CountBlank(Worksheets("Invoice").Range("B3:B8")) > 0 Then
        MsgBox "Fill in all invoice details (B3:B8) before saving.", vbExclamation
        Cancel = True                                ' stop the save
    End If
End Sub

Setting Cancel = True in a “Before” event stops the action. The same works in BeforeClose, BeforePrint and Worksheet_BeforeDoubleClick.

Useful events at a glance

Event Where Typical use
Workbook_Open ThisWorkbook Go to a start sheet, refresh data, show a form
Workbook_BeforeSave ThisWorkbook Check required fields, stamp “last saved by”
Workbook_SheetChange ThisWorkbook One handler for changes on any sheet
Worksheet_Change Sheet Timestamps, auto-format, dependent updates
Worksheet_SelectionChange Sheet Highlight, show help text for the selected column
Worksheet_BeforeDoubleClick Sheet Tick boxes: double-click toggles ✓ (set Cancel = True)
Worksheet_Activate Sheet Refresh a pivot when the sheet is opened

Where people go wrong

  • Nothing happens: code is in a normal module, the procedure name is misspelt, or macros/events are disabled (EnableEvents left off).
  • Excel freezes: the event changes a cell, which fires the event again, forever. Use EnableEvents = False.
  • Undo stops working: any macro that changes cells clears Excel’s undo history. Mention this to users of event-driven sheets.
  • Formulas don’t fire Worksheet_Change: recalculated values don’t count as changes. Use Worksheet_Calculate for that.

Practice

The workbook has a task tracker with automatic timestamps, a codes column that converts to uppercase, double-click tick boxes and a BeforeSave check. Open the code behind each sheet to see where everything lives.

Next: UserForms — your own data-entry windows with dropdowns, validation and buttons.

📎 Practice files for this article

  • 📄
    Events workbook (.xlsb, macros)A task tracker that timestamps edits, uppercases codes and ticks on double-click — the code is behind the Tasks sheet.
    ⬇ XLSB · 16 KB

Free to use for learning. Files with macros (.bas) are plain text — import them with Alt+F11 → File → Import File, and always test on a copy.

✨ Ask AI about this article

Stuck on a step? Ask a question and the AI answers using this article.

Free · AI can be wrong

Leave a Reply

Your email address will not be published. Required fields are marked *