· Workpaper Management · 10 min read

Tab Normalizer: Clean Up Messy Sheet Names and Sort Tabs in One Click

Strips leading and trailing spaces from every sheet name, then optionally sorts tabs alphabetically. Handles name collisions gracefully so you don't break the workbook.

Share:

TL;DR: You inherit a workbook where five tabs are named " Sched-A ", three have trailing spaces, and the tab order is whatever the prior preparer felt like. One macro strips every space and sorts the whole workbook A→Z — or just cleans the names and leaves the order alone. Your choice, one prompt.

The Problem

You open the Henderson workpaper from last year. The tab bar reads: " Sched-A ", "Depreciation ", " Fixed Assets", "NOL ". Sorting them alphabetically means 15 minutes of drag-and-drop — and every time you miss the drop target, the tab flies to the wrong end of the workbook. Even worse, you can’t tell if "Sched-A" and " Sched-A " are the same tab or a duplicate because the spaces blend into the tab width at small sizes.

Excel gives you no “Sort Tabs” button and no “Trim Tab Names” command. It’s a manual chore that wastes ten minutes on every inherited file. This macro does both in under a second.

#Prerequisites & Setup

What you’ll need:

  • Excel 2016+ (desktop)
  • A workbook with multiple sheets — any workbook, any content
  • No special preparation — the macro reads sheet names, not cell data

Limitations:

  • Only affects ThisWorkbook — the workbook containing the macro. Store in Personal Macro Workbook to run on any file
  • Trims leading/trailing spaces only — does not remove spaces within sheet names (e.g., "Fixed Assets" stays "Fixed Assets")
  • Sheets whose trimmed name would collide with an existing sheet name are skipped — the macro warns you with the specific conflict names
  • Sorting is case-insensitive A→Z — "sched-a" and "Sched-A" sort together
  • Very-hidden sheets (xlSheetVeryHidden) are included in trimming and sorting — these are often VBA data sheets and renaming them may break macros that reference them by name

#The Macro

Option Explicit

Sub TabNormalizer()
    ' ── Tab Normalizer ─────────────────────────────────
    ' Strips leading and trailing spaces from every sheet
    ' name. Optionally sorts sheets A→Z. Warns and skips
    ' if a trimmed name would collide with an existing
    ' sheet name (" Sched-A " and "Sched-A" can't both
    ' live in the same workbook — the macro keeps the
    ' clean one and skips the messy one).
    ' ────────────────────────────────────────────────────

    ' ── State management ───────────────────────────────
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual

    ' ── Variables ──────────────────────────────────────
    Dim ws As Worksheet
    Dim trimmedName As String
    Dim trimmedCount As Long
    Dim collisionCount As Long
    Dim collisionList As String
    Dim sortChoice As VbMsgBoxResult
    Dim i As Long, j As Long
    Dim hasCollision As Boolean

    ' ── Error handling ─────────────────────────────────
    On Error GoTo CleanUp

    ' ── Step 1: Ask about sorting ──────────────────────
    sortChoice = MsgBox("Sort sheets alphabetically after " & _
        "trimming?" & vbCrLf & vbCrLf & _
        "Yes = Sorted A→Z" & vbCrLf & _
        "No  = Trim only, keep current order", _
        vbYesNo + vbQuestion, "Sort Order")

    ' ── Step 2: Trim leading and trailing spaces ───────
    trimmedCount = 0
    collisionCount = 0
    collisionList = ""

    For Each ws In ThisWorkbook.Worksheets
        trimmedName = Trim(ws.Name)

        ' Already clean — nothing to do
        If trimmedName = ws.Name Then GoTo NextSheet

        ' Check if trimmed name would collide with an
        ' existing sheet (case-insensitive comparison)
        hasCollision = False
        For i = 1 To ThisWorkbook.Worksheets.Count
            If i <> ws.Index Then
                If StrComp(ThisWorkbook.Worksheets(i).Name, _
                    trimmedName, vbTextCompare) = 0 Then
                    hasCollision = True
                    Exit For
                End If
            End If
        Next i

        If hasCollision Then
            ' Name collision — warn and skip
            collisionCount = collisionCount + 1
            collisionList = collisionList & "  • " & _
                Chr(34) & ws.Name & Chr(34) & _
                " → " & Chr(34) & trimmedName & _
                Chr(34) & " already exists" & vbCrLf
        Else
            ' Safe to rename
            ws.Name = trimmedName
            trimmedCount = trimmedCount + 1
        End If

NextSheet:
    Next ws

    ' ── Step 3: Sort sheets if requested ───────────────
    If sortChoice = vbYes Then
        ' Bubble sort by repositioning sheets left-to-right
        For i = 1 To ThisWorkbook.Worksheets.Count - 1
            For j = i + 1 To ThisWorkbook.Worksheets.Count
                If StrComp(ThisWorkbook.Worksheets(i).Name, _
                    ThisWorkbook.Worksheets(j).Name, _
                    vbTextCompare) > 0 Then
                    ThisWorkbook.Worksheets(j).Move _
                        Before:=ThisWorkbook.Worksheets(i)
                End If
            Next j
        Next i
    End If

    ' ── Step 4: Report ─────────────────────────────────
    Dim msg As String

    If trimmedCount = 0 And collisionCount = 0 Then
        msg = "All sheet names are already clean." & vbCrLf
    Else
        msg = "Trimmed " & trimmedCount & " sheet name(s)." & vbCrLf
    End If

    If collisionCount > 0 Then
        msg = msg & collisionCount & " sheet(s) skipped " & _
              "(name would collide):" & vbCrLf & collisionList & vbCrLf
    End If

    If sortChoice = vbYes Then
        msg = msg & "Sheets sorted A→Z."
    Else
        msg = msg & "Sheet order unchanged."
    End If

    MsgBox msg, vbInformation, "Tab Normalizer"

CleanUp:
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic

    If Err.Number <> 0 Then
        MsgBox "Error " & Err.Number & ": " & Err.Description, _
               vbCritical, "Macro Error"
    End If
End Sub

#How It Works

#Trimming runs without asking — it’s the one thing nobody wants to keep

The macro doesn’t ask “Do you want to trim spaces?” because nobody has ever said yes to keeping " Depreciation " as a tab name. Leading and trailing spaces in sheet names are never intentional — they’re artifacts of copy-pasted tab names, imported data, or a sloppy rename. The macro strips them first, then asks one question: sort or not?

This is what the “no code editor” rule looks like in practice. The macro reads the workbook, figures out what’s wrong, and fixes it. The only thing it asks is the one thing it genuinely can’t know: whether you prefer alphabetical order or whatever order the tabs are already in.

#Name collisions — the case where trimming creates a duplicate

What happens if your workbook has both "Sched-A" and " Sched-A "? After trimming, both would want the name "Sched-A" — and Excel doesn’t allow duplicate sheet names.

The macro catches this with a pre-rename check:

For i = 1 To ThisWorkbook.Worksheets.Count
    If i <> ws.Index Then
        If StrComp(ThisWorkbook.Worksheets(i).Name, _
            trimmedName, vbTextCompare) = 0 Then
            hasCollision = True
            Exit For
        End If
    End If
Next i

If a collision is detected, the macro skips the rename and adds the conflict to a list. The final message box shows every collision so you can decide what to do manually:

Trimmed 5 sheet name(s).
2 sheet(s) skipped (name would collide):
  • " Sched-A " → "Sched-A" already exists
  • "  NOL" → "NOL" already exists

Sheets sorted A→Z.

The macro intentionally leaves the collision unresolved. It could pick a winner (rename the messy one to "Sched-A (2)") but that would hide the fact that you have two sheets that might be the same workpaper — one of them might be an old draft someone was supposed to delete. The warning keeps it visible.

#The sort is a simple bubble sort — and it’s fast enough

VBA has no built-in Sort method for the Worksheets collection. The macro uses a bubble sort — the algorithm every CS 101 student learns — because it’s clean, readable, and fast enough for 50 sheets:

For i = 1 To ThisWorkbook.Worksheets.Count - 1
    For j = i + 1 To ThisWorkbook.Worksheets.Count
        If StrComp(ThisWorkbook.Worksheets(i).Name, _
            ThisWorkbook.Worksheets(j).Name, _
            vbTextCompare) > 0 Then
            ThisWorkbook.Worksheets(j).Move _
                Before:=ThisWorkbook.Worksheets(i)
        End If
    Next j
Next i

The Move Before:= repositions the sheet in the tab bar. On a 30-sheet workbook, this completes in under half a second. No Scripting.Dictionary, no quicksort, no external references — just two loops and a string comparison that works on every Excel install since 2003.

#StrComp with vbTextCompare — the case-insensitive sort that handles Unicode

Three decisions went into the comparison:

  1. StrComp instead of >: StrComp returns -1, 0, or 1 — it’s a three-way comparison function designed for sorting. Using > with Option Compare Text would also work but requires a module-level directive that affects every comparison in the module. StrComp localizes the behavior to the exact comparison you want.

  2. vbTextCompare instead of vbBinaryCompare: Case-insensitive sorting means "fixed assets" and "Fixed Assets" sort together. In a tax workpaper, nobody cares about the capitalization of tab names — they care about finding the right tab.

  3. No special handling for numbers: "Sched-A" and "Sched-E" sort alphabetically, not by section letter. If your workpapers use "Sched-01" through "Sched-15", they won’t sort 01, 02, 03... 10, 11 — they’ll sort 01, 02, 03, 10, 11... 15 because string sorting compares digit-by-digit. For most tax workbooks, this is fine. The Adapt It section shows how to handle numbered prefixes if you need it.

#The message box tells the full story — no silent fixes

Every tab-normalizing action is reported: how many were trimmed, how many collided, and whether sorting happened. If the result is "All sheet names are already clean." with "Sheet order unchanged.", you know the workbook was already in order and the macro did nothing harmful. If you expected 8 trims and got 2, the collision list tells you exactly which sheets conflicted.

#Adapt It

Get the next macro in your inbox

One copy-paste-ready macro recipe every two weeks. No spam, no VBA theory — just automation that saves you time.

One macro recipe every two weeks. Unsubscribe anytime.

E

Excel Macro Guy

Excel enthusiast · married to an accountant

I love Excel. My wife is an accountant. Every busy season, I watch her wrestle with workpapers and think "a macro could do that in half a second." So I build them. She tests them on real client data. What survives gets published here.

More about me →