🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Freeze Panes in Excel — Lock the Header Rows Without Freezing the Wrong Ones

|

VBA Freeze Panes in Excel — Lock the Header Rows Without Freezing the Wrong Ones

TL;DRActiveWindow.FreezePanes = True locks everything above and to the left of the active cell so it stays put while the rest scrolls. Two things surprise people: it freezes relative to whichever cell is selected, so you must position the active cell first (select A2 to freeze row 1, B2 to freeze row 1 and column A); and it lives on the window, not the sheet, which is why it is ActiveWindow.FreezePanes and why a second window on the same file has its own freeze. Turn it off with = False, and un-freeze before re-freezing somewhere new.

' FreezePanes freezes everything above and left of the ACTIVE cell.
Application.Goto Range("A2"), Scroll:=True  ' freeze the top row: put the active cell BELOW it
ActiveWindow.FreezePanes = True

' Freeze the top row AND the first column: active cell at B2
Worksheets("Report").Activate
Range("B2").Select
ActiveWindow.FreezePanes = True

' Unfreeze:
ActiveWindow.FreezePanes = False

FreezePanes is the code version of View > Freeze Panes — the setting that keeps your header row on screen when you scroll down a thousand rows of data. It is the one view tweak worth scripting into every report macro, because it turns a wall of numbers into something someone can actually read. It is also one of the few VBA properties where you legitimately have to touch the active cell and the active window, which is exactly why it behaves in ways that catch people out.

What you'll learn

  • The mental model — freeze locks a corner of the view, and lives on the window
  • The one rule that matters — it freezes relative to the active cell, so position it first
  • Why it is ActiveWindow.FreezePanes and each New Window has its own freeze
  • Turning it off, and why you must un-freeze before re-freezing
  • FreezePanes versus Split, and a select-free path through SplitRow
  • Where freeze belongs in a report macro — last, on the sheet you just built

The mental model: locking a corner of the view

Freezing panes does not change the data, the sheet, or a single cell — it changes the window you are looking through. Picture the grid split into four quadrants by one horizontal and one vertical line. The top-left quadrant is pinned; the other three scroll under it. FreezePanes draws those lines and pins the corner. That is the whole idea, and it carries two consequences that explain everything else: the split has to be positioned somewhere, and it belongs to the window, because a window is what does the scrolling.

Hold on to "it is a view setting on the window," and the two classic surprises — freezing the wrong rows and the freeze not sticking — stop being mysteries.

The rule that matters most: it freezes at the active cell

Here is the mistake behind almost every "it froze the wrong rows" bug. FreezePanes does not take a row number or a range. It freezes everything above and to the left of whatever cell is active at the moment you set it. So the active cell is the control, and if you do not position it, you freeze at wherever the cursor happened to be:

ActiveWindow.FreezePanes = True   ' freezes at the current selection - wherever that is

The rule is to place the active cell just below and to the right of what you want frozen, then set the property:

  • Freeze the top row → select A2 (everything above row 2 is frozen).
  • Freeze the first column → select B1.
  • Freeze both the top row and first column → select B2.

That is why the recorded macro always shows a Range(...).Select right before ActiveWindow.FreezePanes = True. Freezing is one of the rare cases where selecting a cell is not a code smell — the selection is the argument. Get the active cell right and the freeze lands exactly where you want it.

It lives on the window, not the sheet

Notice the object: ActiveWindow.FreezePanes, never Worksheet.FreezePanes. Freezing is a property of the window through which you view a sheet — and a sheet can be shown in more than one window. Open View > New Window on the same workbook and you get a second window with its own freeze state; one can have the top row frozen and the other not. This is why a freeze can seem "not to stick": you set it on one window and are looking at another.

For a macro, the practical consequence is that the sheet you want to freeze must be active in the window you are setting — you cannot reliably freeze the panes of a sheet the user is not looking at. That makes FreezePanes one of the few places where reaching for ActiveWindow and Activate is correct rather than lazy: the window is genuinely the thing you are configuring. Activate the sheet, position the active cell, set the property.

Turning it off and re-freezing

Un-freezing is a plain assignment:

ActiveWindow.FreezePanes = False

The subtlety is re-freezing. Setting FreezePanes = True when panes are already frozen does nothing — Excel does not move an existing freeze to the new active cell. So to move a freeze, you must clear it first, reposition the active cell, then set it again:

ActiveWindow.FreezePanes = False   ' clear the old freeze
Range("C3").Select                 ' reposition
ActiveWindow.FreezePanes = True    ' freeze at the new corner

Skip the = False line and your "new" freeze is ignored while the old one silently stays. Make un-freeze the first step whenever a macro re-applies a freeze it may have set on a previous run.

FreezePanes versus Split, and a select-free path

FreezePanes locks the panes solid. ActiveWindow.Split (with SplitRow and SplitColumn) creates draggable split bars instead — the panes are separated but the user can resize them, and they do not lock. Most report macros want a freeze, not a split. But the split properties give you a tidy way to freeze without selecting a cell, which some people prefer for readability:

ActiveWindow.SplitRow = 1        ' split below row 1
ActiveWindow.SplitColumn = 1     ' split after column A
ActiveWindow.FreezePanes = True  ' turn the split into a freeze - no Select needed

Setting SplitRow/SplitColumn and then FreezePanes = True freezes at the split position, so you never touch the active cell. Either style is fine; use whichever reads more clearly to you. The select-free version avoids leaving the user on a surprise cell after the macro runs.

Where freeze belongs in a report macro

Freeze is a finishing touch, so it goes last — after you have written the data, applied the number formats, and run AutoFit. Freezing early then inserting or deleting rows can shift where the freeze lands. The reliable pattern is: build the sheet, size it, activate the sheet you built, position the active cell (or set the split), then ActiveWindow.FreezePanes = True. Do not trust the hard-coded Range("A2").Select a recorder wrote on a different sheet layout — decide the freeze corner from the report you actually generated, and place the active cell there deliberately.

How ExcelMaster helps

Freeze Panes is the setting that makes a generated report usable at a glance and also the one that quietly freezes row 1 through row 40 because the active cell was somewhere unexpected, or seems not to work because it was set on the wrong window, or refuses to move because the old freeze was never cleared.

ExcelMaster lets you say what you want kept on screen — "freeze the header row," "lock the first two columns and the top row" — and it writes the freeze as the last step of the routine: it activates the right sheet, positions the active cell (or sets SplitRow/SplitColumn for a select-free freeze) so the split lands exactly where you meant, and clears any old freeze before applying a new one. You keep the workbook and the code.

Frequently asked questions

Why does VBA freeze the wrong rows?

Because FreezePanes freezes relative to the active cell, not a row number, and the active cell was not where you thought. It locks everything above and to the left of the selection. Position the active cell first — select A2 to freeze the top row, B2 to freeze the top row and first column — then set ActiveWindow.FreezePanes = True.

How do I freeze the top row in VBA?

Make the active cell A2 (one row below the header), then freeze: Range("A2").Select followed by ActiveWindow.FreezePanes = True. Or skip the selection entirely with ActiveWindow.SplitRow = 1 then ActiveWindow.FreezePanes = True. The sheet must be active in the window you are setting.

How do I unfreeze panes in VBA?

Set the property to False: ActiveWindow.FreezePanes = False. Note that to move a freeze you must un-freeze first — setting FreezePanes = True while panes are already frozen does nothing, so clear the old freeze, reposition the active cell, then set it again.

Why is ActiveWindow.FreezePanes not working?

Usually one of three things. The sheet you want to freeze is not active in the current window — activate it first. Or panes are already frozen, so setting True again is ignored — set False, reposition, then True. Or you are looking at a different window than the one you set: freeze is a per-window property, and New Window creates a second window with its own state.

Is FreezePanes on the worksheet or the window?

The window. It is ActiveWindow.FreezePanes, not a worksheet property, because freezing configures how a window scrolls over a sheet. The same sheet shown in two windows (via View > New Window) can have different freeze states. That is also why the sheet must be active in the window you are configuring.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-10.

Related guides: VBA AutoFit · VBA Wrap Text · VBA Worksheets · VBA Column Width · VBA Range