You have a Word document with bookmarks that are not visible in the default Bookmarks dialog or in the document body. These hidden bookmarks may reside in headers, footers, text boxes, comments, or other story ranges. The standard ActiveDocument.Bookmarks collection only covers the main document story. To access all bookmarks, you must use VBA to iterate through every story range in the document. This article explains how to write a VBA macro that loops through all story ranges and retrieves every bookmark, including those in hidden parts of the document.
Key Takeaways: Iterating All Word Bookmarks in VBA
- ActiveDocument.StoryRanges enumeration: Loops through all 11 story types including headers, footers, and text boxes to access hidden bookmarks.
- Range.Bookmarks collection: Each story range has its own Bookmarks collection that may contain bookmarks invisible in the main document.
- StoryType constants (wdMainTextStory, wdPrimaryHeaderStory, etc.): Identify which story range a bookmark belongs to when iterating.
Why Standard Bookmarks Iteration Misses Hidden Bookmark
Word stores content in multiple story ranges. The main document body is one story. Headers, footers, footnotes, endnotes, comments, text boxes, and other containers are separate stories. The ActiveDocument.Bookmarks property returns only bookmarks in the main story range. Bookmarks placed in a header, footer, or text box are not visible there. To find them, you must access each story range individually.
A common cause of missing bookmarks is using the Insert Bookmark dialog while the insertion point is inside a header or footer. Word creates the bookmark in that story range, not in the main document. The bookmark still exists but is hidden from the standard bookmarks list. VBA can reach it by iterating all story ranges.
Another scenario is bookmarks inside a drawing canvas or a text box anchored to a paragraph. These bookmarks belong to the text box story range, not the main document. Only by enumerating story ranges can you capture them.
Writing a VBA Macro to Iterate All Bookmarks in All Story Ranges
You need a VBA macro that loops over every story range in the document and then loops over the bookmarks in each range. The macro below prints the bookmark names and their story type to the Immediate window. You can modify it to perform other actions such as deleting, counting, or copying bookmarks.
Step 1: Open the VBA Editor and Insert a Module
- Open the Visual Basic Editor
Press Alt + F11 in Word to open the VBA editor. - Insert a new module
In the Project Explorer, right-click your document name or Normal.dotm, choose Insert, then Module. A blank code window appears.
Step 2: Paste the Macro to Iterate All Bookmark
- Copy the macro code
Copy the following VBA code into the module:Sub ListAllBookmarksAllStories() Dim rngStory As Range Dim bmk As Bookmark Dim storyType As String For Each rngStory In ActiveDocument.StoryRanges Select Case rngStory.StoryType Case wdMainTextStory: storyType = "Main Document" Case wdPrimaryHeaderStory: storyType = "Primary Header" Case wdFirstPageHeaderStory: storyType = "First Page Header" Case wdEvenPagesHeaderStory: storyType = "Even Pages Header" Case wdPrimaryFooterStory: storyType = "Primary Footer" Case wdFirstPageFooterStory: storyType = "First Page Footer" Case wdEvenPagesFooterStory: storyType = "Even Pages Footer" Case wdFootnotesStory: storyType = "Footnotes" Case wdEndnotesStory: storyType = "Endnotes" Case wdCommentsStory: storyType = "Comments" Case wdTextFrameStory: storyType = "Text Boxes / Frames" Case Else: storyType = "Other" End Select For Each bmk In rngStory.Bookmarks Debug.Print storyType & ": " & bmk.Name Next bmk Next rngStory End Sub - Run the macro
Press F5 or click Run in the toolbar. Switch to the Immediate window (Ctrl + G) to see the list of all bookmarks with their story type.
Step 3: Modify the Macro for Other Actions
To delete all bookmarks in hidden parts, replace the Debug.Print line with bmk.Delete. To count them, increment a counter variable. To copy bookmark names to a new document, collect them in a string array and write them to a separate document.
Common Issues When Iterating Hidden Bookmark
The Macro Shows No Bookmarks Even Though I Know They Exist
The most likely cause is that the bookmark is inside a linked text box or a group shape. Word’s StoryRanges collection does not include linked text box chains beyond the first. To reach bookmarks in linked text boxes, you must follow the NextStoryRange property of the text frame story range. Add a loop that checks rngStory.NextStoryRange until it returns Nothing.
Bookmarks in Comments Are Not Listed
Comments have their own story range wdCommentsStory. The macro above includes it. If you still do not see comment bookmarks, ensure the comment is not inside a nested container such as a text box placed in the comment. Run the macro again after selecting the comment area and checking the story type in the Immediate window.
Macro Returns Duplicate Bookmark Names
Word allows the same bookmark name to exist in different story ranges. The standard Bookmarks dialog only shows the main story bookmark. When you iterate all stories, you get each occurrence. To deduplicate, use a Collection or Dictionary object to store names and skip duplicates.
Word Story Ranges vs Bookmarks Dialog: What Each Captures
| Item | ActiveDocument.Bookmarks | StoryRanges Enumeration |
|---|---|---|
| Main document body | Yes | Yes |
| Headers and footers (all types) | No | Yes |
| Footnotes and endnotes | No | Yes |
| Comments | No | Yes |
| Text boxes and frames (first in chain) | No | Yes |
| Linked text boxes beyond first | No | No (requires NextStoryRange) |
| Drawing canvas shapes | No | No (use CanvasShapes collection) |
The standard Bookmarks dialog only returns the first row. The StoryRanges enumeration covers most hidden areas but not linked text boxes beyond the first or drawing canvas shapes. For those, you need additional VBA code using CanvasShapes or InlineShapes collections.
You can now write a VBA macro that iterates all bookmarks in a Word document including those in headers, footers, text boxes, comments, and other hidden parts. The key is using ActiveDocument.StoryRanges and checking each range’s Bookmarks collection. For linked text boxes, extend the loop with NextStoryRange. As a next step, modify the macro to export all bookmark names and their story types to a table in a new document for auditing. An advanced tip: use the wdTextFrameStory constant combined with a Do While loop on NextStoryRange to capture bookmarks in chained text boxes that the basic enumeration misses.