
📎 This article includes 1 downloadable practice file ↓
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
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:
Targetis every cell that changed — maybe one, maybe 500 pasted at once. Loop over it instead of assuming one cell.Intersectlimits the reaction to column D, so editing column A doesn’t stamp anything.EnableEvents = Falsestops our own write to column E from triggering Worksheet_Change again.
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 (
EnableEventsleft 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_Calculatefor 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.
Stuck on a step? Ask a question and the AI answers using this article.