Heading

This is some text inside of a div block.
This is some text inside of a div block.
This is some text inside of a div block.
min read

Insert new paragraph below any heading

Word • Macros • Editing
Peter Ronhovde
30
min read

We create a new paragraph at the end of the current heading for either standard or derived heading styles. This macro is nice for appending ideas in novel notes or an outline document.

Thanks for your interest

This content is part of a paid plan.

Insert a new empty paragraph below any heading

We extend a previous macro that inserts a new empty paragraph at the end of the current heading content. The macro works regardless of the initial insertion point position in the heading content, and this version further accounts for derived heading styles, missing headings, as well as a few other tid bits.

Huh? Isn't that what the Return key is for? Just—

We're streamlining the process, so you get the words on the screen faster.

Example of adding a new paragraph at the end of the current heading
Example of adding a new paragraph at the end of the current heading

This macro is also a variation of a previous macro to insert a new empty paragraph above or below the current paragraph. The goal is to fill our toolbox with various tools to improve the overall efficiency of small editing tasks.

What are the manual steps?

Thinking about the manual steps required to accomplish a task is a good place to start when creating a new macro. It will give us a hint as to whether it's worth the time based on how many steps we're actually saving. With that said, I've created several macros on a whim on a detour into productive procrastination, but I ended up using them a lot more than I ever expected. Don't discount the utility or at least the convenience of simple macros.

What are the manual steps?

  1. Move to the end of the last paragraph of the heading content (slow)
  2. Press the Return key
  3. Change the paragraph style (if needed; also slow for most styles)

Step 1 is slower than it seems based on the single step it takes in the list. Use the mouse is usually slow compared to the keyboard.

Issues with the GoTo dialog and headings

Even if we use the GoTo dialog via the F5 shortcut (or Control+G in Windows or Command+Option+G on a Mac), it's a poor solution for anything more than a few edits.

  • The dialog is slow for heading navigation.
  • It does not respect derived heading styles (so they show up in the Navigation Pane) such as Act or Chapter based on Headings 1 or 2, respectively.
  • It is less clumsy for any long-distance navigation since you need to know heading count offset based on your current position.

In many cases, it's no faster than just grabbing the mouse and scrolling or clicking on a heading in the Navigation Pane. It works, but it's an example of stuffing too much into a single dialog. It becomes just a multipurpose tool for a bunch of cases rather than a productive one when we're making a thousand edits in a novel or a notes document.

We created separate macro to quickly jump to a nearby heading which would significantly speed up step 1 above for nearby headings, but why not just tap a quick shortcut to a macro tailored to complete all the steps at once? Done. Just start typing.

Difference with VBA

The manual steps can guide us when developing a macro, and we could choose to construct a macro following the exact manual procedure. This is essentially what recording a macro does automatically, but the best VBA steps often do not directly mirror the manual process. VBA knows the structure of the document, so it does not need to interact with the document through the keyboard and mouse like we do. Occasional issues pop up, like in the macro for this article, where we need to add extra steps to correct for certain special cases, but in general, it's better to take advantage of VBAs more targeted commands to accomplish an editing task.

Create the empty macro

Open the VBA Editor (Alt+F11 in Windows or Option+F11 on a Mac) and create the following empty macro. A previous post also covers how to create it via the macro dialog accessed through the ribbon interface.

Sub NewParagraphBelowCurrentHeading()
' Insert a new paragraph below at the end of the current heading content
' allowing for derived heading styles

End Sub

VBA ignores the comment text on the second line after the single quote character. It's common to include few lines to explain the purpose and function of the macro beyond a descriptive name. For some macros, it's further helpful to mention any special features or considerations for later reference. We start our macro steps on the empty line.

Understanding common VBA object thingys

VBA represents Word document elements internally as virtual "objects". These objects are treated as composite data "types", so we can declare variables and assign them to specific document elements. Each object consists of data (called "properties") and actions (called "methods") which we use to control the associated document content. Generally, speaking the VBA representations use the same name as the general document element but with a capital letter. For example, a paragraph is what we see on the screen, but a Paragraph is VBAs internal representation of it.

What is the Selection?

A (lowercase) selection is what we see on the screen when we use the mouse or keyboard to select some document content. Roughly speaking, a selection spans a range of document content. We will not consider non-contiguous or block selections in most cases since VBA does not currently work well with them.

VBA represents it with an object called the Selection (capital S), but VBA also considers an insertion point (the blinking I-bar waiting for you to type) to be an empty selection. The Selection has many methods we can use to control its position or extent in the document, but it also relevant actions such as deleting the spanned content and more. The Selection is a special case of a Range object, but only one Selection exists per document.

What is a Range?

Humans do not intuitively think of ranges as Word document elements, but they are a convenient generalization of a selection.

VBA calls its object a Range (capital R). They are invisible to the user until we select it or make some specific document change using its properties or methods. At a root level, a Range consists of Start and End position, and we can create multiple range variables to carry out whatever macro logic we need. At the end of the macro, the variables effectively disappear into the computer world leaving only the changes that were made to the document while the macro was running.

What is a Bookmark?

Physically, a bookmark is a page reference in a book marked with a slip of paper or a clip.

In VBA, a Bookmark (with a capital B) is a Range of document content. It can refer to a specific document position where the Start and End positions are equal (an "empty" range), but it can also span document content. While the Range aspect is perhaps a little unintuitive when thinking about a physical bookmark, it is a convenient extension of the idea in VBA.

A Bookmark is its own thing (object type) in VBA, so it further includes some convenient properties like Range, Start, or End to quickly access the underlying range information. We can also quickly Copy, Delete, or Select the bookmark range. We do not add, remove, or otherwise manipulate bookmarks in this macro, so we'll leave any further commentary for later articles.

What is a Paragraph?

A paragraph is the content we see on the screen bounded by usually invisible paragraph markers (except for the first paragraph of the document).

In VBA, a Paragraph is similarly a range of document content that ends with a paragraph marker, but as with all VBA objects, a Paragraph includes some extra properties like the Style or OutlineLevel as well as some methods specialized for tracking or manipulating paragraphs.

New paragraph below a standard heading

What do we do? We need to somehow span the heading range to find the End position. Then we insert our new paragraph and make the more minor modifications.

Simple heading range using a bookmark

The knee-jerk method to navigate between headings is to use any of the GoTo methods along with the What option. In this macro, we would use the heading constant wdGoToHeading from the table of possible GoTo items and throw in a range variable or two to track and span the heading range. We introduced the GoTo methods in a little more detail in a previous article, but the earlier version of the macro only worked for standard Word heading styles Heading 1 – 9 because it was based on the default behavior of the GoToNext method of the Selection.

Fortunately, Word "secretly" includes a pre-defined list of hidden bookmarks which it tracks and updates internally in real time. For our purposes, the \HeadingLevel bookmark allows us to quickly access the heading range around the Selection (or the current range variable).

Issues with the heading range

Setting the correct range for this macro is more involved than it appears at first glance (which is why you have me along for the ride).

Issues with paragraph markers and ranges

In order to make this macro work as intuitively as possible, we should understand how Word spans various heading and other ranges using the advertised \HeadingLevel bookmark or the document range.

What's the problem?

One minor but annoying roadblock is the paragraph marker at the end of the document. It is not always included in an extended range, but it is included in the document range (when using the current document's Range property) except when it's not (when using the \Doc pre-defined Bookmark).

See where we're headed. Confusion Lane winding through Construction City during rush hour. It's not that we can't work around the end-of-document paragraph marker, but we want the logic to work for every exit (any of the cases). Add the necessary presentation aesthetics for an article, and we have some work to do.

Ughhh.

Sounds like a fun excursion, so let's mark the check the construction signs. Some overlap exists, but they are listed separately for clarity. The format is: Initial document state → Resulting effect on the End position of our desired heading range.

  • Extend heading range somewhere in the "middle" of the document where more headings exist after the current location → Ending paragraph marker of the heading content is automatically included in the range like what happens with normal range extensions.
  • Extend heading range at the end of document where no later headings exist after the current location → End-of-document paragraph marker is not automatically included in the range.
  • No headings exist in the document → Heading level bookmark still exists and spans all document content, but the range does not include the end-of-document paragraph marker.
  • Initial selection exists → Range extension seems to be based on the Start position of the Selection which follows the other observations.

Two more obscure range issues include:

  • Insertion point is at the last character of the document even if it is below a heading → Heading level bookmark does not exist (causes an error)
  • An empty range cannot be positioned after the end-of-document paragraph marker, but the end of document paragraph marker may still be manually included in a range.

While I cannot assert any of these behaviors are necessarily wrong—more like design decisions—some of them are not obvious, and it takes some effort to find a consistent set of macro steps that does not include multiple conditional statements to handle all the possible cases.

Several of these may cause logical detours, so we need to drive carefully.

Define a heading range

The first task in many robust macros is to define a working range variable.

Dim rHeading As Range

Remember Dim declares a variable in VBA, and "As Range" tells VBA what type the variable is. As a personal reminder of the type of data it stores, I usually include an "r" as the first letter of any Range variables. Often, I even just use "r" in my personal macros if only one range variable exists.

Object thingys in VBA can be used as data types just like regular numbers (Integer, Currency, etc.) or plain text (as a String). If you want to force yourself to be specific with variable data types, you can specify Option Explicit at the top of the macro file. It is recommended when you write more robust macros since they more clearly communicate what we intend to do with a variable. Things get a little messier because VBA also allows generic variables (as "Object" or "Variant") even when declaring them which half defeats the purpose of requiring them.

Setting the heading range

Considering all the special cases and issues mentioned above, a rough pseudo-code to identify a potential heading range is something like:

If the heading bookmark exists Then
' Extend the working range over the heading
Otherwise
' Extend the working range over the whole document
End the range definition

This pair of range assignments is more complicated than most others we've defined, and we're not done yet (see a previous article for more about VBA conditional statements).

After this conditional statement, the goal is to have a well-defined and consistent range stored usually corresponding to the current heading content. Consistency is important because the steps after the range definition need a clear state. It would be nice to limit any additional conditional steps required to make the macro work correctly.

Technically, using the entire document range in the "otherwise" (Else) case is only correct for a document with no headings. We will only work with the End position of the range, so the distinction is not important. Adding extra steps to detect and then correct the beginning of the range when we will not use it is superfluous. This case can occur whether or not any headings exist in the document, so properly detecting it complicates the explanation. We will note the minor inconsistency in a comment to be clear if we ever come back to the macro.

Check whether the bookmark exists

The Selection has a Bookmarks collection storing all bookmarks spanned by the current Selection including any pre-defined Word bookmarks.

Selection.Bookmarks ' Not done ...

Not all pre-defined bookmarks will exist at a given location in the document, so we need to check whether our Heading level bookmark exists before trying to use it. Otherwise, the bookmark name will refer to Nothing causing the macro will crash (and quit immediately). The method is conveniently called Exists, so we just need to provide the bookmark name as plain text in double quotes (called a "string").

Selection.Bookmarks.Exists("\HeadingLevel")

This method will return a True or False (Boolean) value based on whether the bookmark exists. As such, we can directly use it in our previous conditional statement.

Get the bookmark range

After we know the bookmark exists, we can assign it to the rHeading working range. We begin again with the Bookmarks collection, but we specify the \HeadingLevel bookmark name. Parentheses are required around the name in this command because we need to refer to a property afterward.

Selection.Bookmarks("\HeadingLevel") ' Not done ...

The bookmark is an object itself, so we need to refer to its Range property to properly assign it to the heading range variable.

Selection.Bookmarks("\HeadingLevel").Range ' Still not done ...

Now, we just assign this to our rHeading range variable.

Set rHeading = Selection.Bookmarks("\HeadingLevel").Range

We needed to use the keyword Set in the assignment because a Range is an object as opposed to a regular value like a number.

Allow for a missing heading bookmark

When the heading level bookmark does not exist, we want to extend the working range over the entire document. While not correct for some cases, we only need the correctly find the end of the document. The current document has a shorthand reference called the ActiveDocument which is part of the Application object.

Application.ActiveDocument ' Not done ...

The Application is a top-level object, so we can omit it and just refer to the ActiveDocument. We set the working range based on the Range property of the ActiveDocument.

ActiveDocument.Range ' Still not done ...

Then we assign it to the heading variable like we did above with the bookmark range.

' Set the working range to the entire document
Set rHeading = ActiveDocument.Range
Setting the range conditional statement

Put the bookmark validation and the respective range assignments into the above conditional statement.

If Selection.Bookmarks.Exists("\HeadingLevel") Then
' Extend the working range over the heading using the bookmark
Set rHeading = Selection.Bookmarks("\HeadingLevel").Range
Else
' Extend the working range over the whole document (not exactly correct
' for a document with headings, but we do not use the Start position)
Set rHeading = ActiveDocument.Range
End If

This range assignment was more involved than in past macros. It handles most cases, but we still have an issue to correct.

Correct for omitted end-of-document paragraph marker

The end-of-document paragraph marker will not be included in the extended range for some situations, so we need to correct for it. VBA excludes that paragraph marker, so if we want consistent logic, we need to detect it and ensure a consistent state for the remaining macro steps. One approach is to just manually include it.

Check the next character for a paragraph marker

More specifically, most range extensions will automatically include a paragraph marker in the extended range. For extensions including the end of the document, the end-of-document paragraph marker is not included for certain cases.

How do we fix this?

We want to check whether the next character immediately after our range is a paragraph marker. If so, we're confident the End of our range is at the end of the document. Fortunately, any range variable has a Next property that gives us the next document element.

rHeading.Next ' Not done ...

We can specify any of several units from a standard Word constants table, but the default unit is a character, so we can omit the Units option. Next technically returns the range of the document element, but we need the plain text for the character comparison. We get it using the Text property.

rHeading.Next.Text ' Still not done ...

We define a condition for whether the next character is paragraph marker. A paragraph marker is a special character defined as vbCr in a miscellaneous Word constants table. We want to now whether our character from above is equal to a paragraph marker vbCr.

' Condition checking whether the Next character is a paragraph marker
rHeading.Next.Text = vbCr

A condition looks like assigning a value to a variable in isolation like this, but VBA will interpret it as a True or False (Boolean) value when it's used in a conditional statement. But there is a problem …

What if the Next character does not exist?

Unfortunately, in at least two circumstances, the next character after the insertion point may not exist in the document. If it doesn't exist, the Next reference will return Nothing which will cause an error if we try to check the Text property (or anything else about the range variable). It's not a roadblock, but we first need to check whether Next is Nothing and only attempt to get its character text if it is valid.

If Next character exists Then
' Next character exists, so checking it is okay
End next character validation
How do we check whether the range Is Nothing?

The main advantage of VBA (and Visual Basic, in general) is it strives to read more like English than many other programming languages. It doesn't always hit the mark, but the condition is in the question. We literally use "Is Nothing" for the comparison.

' Is the Next property of the heading range valid?
rHeading.Next Is Nothing

"Is" is a special comparison operator used only for objects. Since unassigned objects have a value of Nothing, we use Is to check whether an object variable Is Nothing.

Only check the character when Next is not Nothing

We actually need the reverse condition. That is, we need something like "Is Not Nothing", but VBA does not allow this phrasing (regular VB allows IsNot, but it doesn't exist in VBA). Instead, we use a (Boolean) Not to flip the True or False result. In VBA, this validation check is:

Not rHeading.Next Is Nothing ' Still not done ...

Not is an "operator" that literally switches True to False and vice versa. This does not read as nicely since we had to place the Not before the condition, but the revised conditional statement skeleton is:

If Not rHeading.Next Is Nothing Then
' Next character exists, so checking it is okay
End If

I tried to avoid this messy validation detour, but it pops up with an empty heading at the end of the document. This is a reasonable, though a little odd, use case; so I cannot omit it and feel confident in calling it a robust macro.

Now, let's check the actual character.

Include the end-of-document paragraph marker

If the next character is a paragraph marker, we want to extend the End position of the heading range over it. The appropriate command is the MoveEnd method.

rHeading.MoveEnd ' Not done ...

We combine the above check with the conditional statement and the command.

' Check whether the next character after the range is a paragraph marker
If rHeading.Next.Text = vbCr Then
' Extend the range over the next paragraph marker
rHeading.MoveEnd
End If

Since the command is brief, we can simplify it into a one-line conditional statement.

' Check whether to extend the range over the next paragraph marker
If rHeading.Next.Text = vbCr Then rHeading.MoveEnd

Finally, we can only apply extend the range if the Next property is valid, so we need to place it inside the Next validation.

' Ensure a consistent state where the range always includes the
' ending paragraph marker due to end-of-document inconsistencies
If Not rHeading.Next Is Nothing Then
' Next character exists, so check whether it is a paragraph marker
If rHeading.Next.Text = vbCr Then rHeading.MoveEnd
End If

This is called a "nested" If statement with one inside another. It's occasionally necessary, but they are generally considered messy. I try to avoid them for presentation purposes, but this is about as clear and concise as I can make it and still be as safe as necessary. A few other approaches exist to correctly handle the last paragraph marker, but I felt this version was one of the clearest for presentation purposes.

We're not off the special cases detour yet though. Another less-obvious issue exists because a range cannot be positioned past the end-of-document paragraph marker. While not a roadblock on its own, it affects the movement commands. What works in the middle of the document may not work at the end. It's annoying to have the insertion point finish on the wrong paragraph.

Store the correct paragraph style

As a convenience, we can store the intended paragraph style to apply to the new empty paragraph at the end of the macro.

Declare the style name variable

Specifically, we will store our style name as plain text (called a "string").

' Store the last paragraph next style
Dim SStyle As String

We've called the variable SStyle because we cannot use the reserved word "Style", and I did not want anything longer. I usually prepend my string variables with an "S" (lowercase "s" if it will change sometime during the macro). This is a personal convention to remind myself about the type of data the variable stores.

Fortunately, VBA conveniently allows us to refer to a style by only its name in many cases, so we do not need to use the Style object type much unless we're actually creating or modifying a style inside a macro.

Get the intended style name

Normally, we refer to the name in double quotes, but we do not know the style of the last paragraph, so we need to store it in a String variable for later reference.

What do we want?

It seems consistent with the intention of the macro to add the new empty paragraph based on the last paragraph of the range. The heading range variable has a Paragraphs collection we can use to refer to the last one.

rHeading.Paragraphs ' Not done ...

We are not required to declare our style name variable, but I prefer to be extra clear in my own macros and on the more robust macro articles. We can add the line, Option Explicit, at the top of the macro file to force all variables to be declared, but even then, we could weasel out of it using generic types. I recommend being specific.

We refer to the last paragraph of the collection, using its Last property.

rHeading.Paragraphs.Last ' Still not done ...

Then we want the Style property of the paragraph. If we just wanted its name, we could assign it to a string variable directly, but we'll take it another logical step before we do that.

rHeading.Paragraphs.Last.Style ' Almost there ...

As a caveat, this reference is a Style type, meaning it's an object, but VBA allows the convenience of assigning it to a string variable. Before we get there, we actually want to store the next paragraph style using the NextParagraphStyle property.

rHeading.Paragraphs.Last.Style.NextParagraphStyle ' Almost there ...

Now we can assign this style to the string variable.

' Store the name of the next paragraph style
SStyle = rHeading.Paragraphs.Last.Style.NextParagraphStyle

VBA automatically just stores the name of the style in the SStyle variable as opposed to all the other stuff making up the Style. We will use this style name at the end of the macro. The equals = sign here only works because we're storing a plain text name. If we were storing the entire Style object, we would need to add a Set to the command.

Insert the new paragraph at the end of the range

That's a lot of setup steps, but we can finally insert the actual empty paragraph.

Move backward one paragraph

We could just insert a paragraph before the current one at this step of the macro, but it would inherit a heading style. We can avoid this simply by moving back to the previous paragraph, so it will inherit that paragraph's style which is much more likely to be correct.

We move back one character just inside the previous paragraph. We need to adjust the End position of the range using the MoveEnd method.

rHeading.MoveEnd ' Not done ...

The default step size is by a single character which is exactly what we want, so no Unit option is needed; however, we need to move backward in the document just before the paragraph marker of the prior paragraph.

' Insert the new paragraph and position the insertion point
' Can go before or after inserting the new paragraph
rHeading.MoveEnd Count:=-1

The Count option specifies how many units to move, and negative values move backward in the document. As with all command options, we assign the -1 value using a colon equals := symbol.

This step is not required before using the following insert paragraph command, but it makes the command order work for almost all use cases.

Insert the new paragraph

We finally insert the new empty paragraph after the heading range using the InsertParagraphAfter method.

rHeading.InsertParagraphAfter

As a quick aside, the InsertParagraph method would not work since it replaces the range content with a paragraph marker (like hitting enter with a selection made in the document). That's bad here since our range spans the entire heading.

Move to the new empty paragraph

We need to move to the new empty paragraph, so we can just start typing. We could use actual move methods, but in this case, it's easier to just collapse the heading range using the Collapse method. The earlier MoveEnd command set up this collapse to work perfectly.

rHeading.Collapse ' Not done ...

Unfortunately, it collapses toward the beginning of the rHeading range by default. We need it to collapse toward the end of the range, so we add the Direction option.

rHeading.Collapse Direction:=wdCollapseEnd

The wdCollapseEnd constant is defined in another very short table of Word constants.

Apply the stored paragraph style

We previously stored the intended paragraph style in the variable SStyle, so now we can assign it to the current paragraph. The heading range is already positioned at the empty paragraph, so we just apply the style. When we have the name, we just set the Style property equal to the name, and VBA interprets all the other style information.

' Set the style of the new paragraph to the stored style
rHeading.Style = SStyle

This command would normally apply the indicated style to every paragraph in the range, but in this case, the range is empty and positioned at an empty paragraph.

If we had not stored the desired "next" paragraph style, it would default to the style of the last paragraph based on our command order.

Select the new empty paragraph

We've made several document changes using the heading range, but its current location is invisible. To make it visible, we use the Select method.

' Select the final insertion point and scroll onto viewscreen
rHeading.Select

The basic behavior of the method is as expected. If the range spans any document content, it is literally selected in the document. In this macro, the range is empty, so it will be selected as an insertion point (the blinking I-bar) waiting for us to type any new text. This effectively moves the current Selection since only one Selection can exist in a document at a time. By default, this command should also scroll the selected content into view on the screen.

Move order is important

The movement scheme using a range collapse is a relatively common technique. The particular command order is important for this macro when working at the end of the document since some other orderings would not leave the insertion point at the correct location (probably one paragraph too early). The chosen command order combined with the more careful range definition up top properly positions the insertion point at the new empty paragraph in essentially all use cases.

Any gotchas?

We've spent a lot of effort catching potential errors, but it still does not hurt to consider what could go wrong.

What about the end of the document?

Several of the above conditions have worked around issues with the end of the document, so we've handled almost every variation. The only exception is an empty document, but I held back on that trivialized case since the macro is already more complicated than I prefer for an article.

What if no later headings exist?

We spent several steps catching a missing heading, so this case should be covered.

Finish the Macro

Now we just put the commands together.

Sub NewParagraphBelowCurrentHeading()
' Insert a new paragraph at the end of the current heading content
' allowing for derived heading styles

' Define the heading range defaulting to the whole document
Dim rHeading As Range
If Selection.Bookmarks.Exists("\HeadingLevel") Then
' Extend the working range over the heading using the bookmark
Set rHeading = Selection.Bookmarks("\HeadingLevel").Range
Else
' Extend the working range over the whole document (not exactly correct
' for a document with headings, but we do not use the Start position)
Set rHeading = ActiveDocument.Range
End If

' Ensure a consistent state where the range always includes the
' ending paragraph marker due to of end-of-document inconsistencies
If Not rHeading.Next Is Nothing Then
' Next character exists, so check whether it is a paragraph marker
If rHeading.Next.Text = vbCr Then rHeading.MoveEnd
End If

' Store the last paragraph next style name
Dim SStyle As String
SStyle = rHeading.Paragraphs.Last.Style.NextParagraphStyle

' Insert the new paragraph and position the insertion point
rHeading.MoveEnd Count:=-1 ' Also works after paragraph insert
rHeading.InsertParagraphAfter
rHeading.Collapse Direction:=wdCollapseEnd

' Set the style of the new paragraph to the stored style
rHeading.Style = SStyle
' Select the final insertion point and scroll onto viewscreen
rHeading.Select
End Sub

I assigned this one to Command+Control+Option+Return in Word for Mac and Control+Win+Alt+Return in Windows. See another article for a workaround on how to assign the latter since the Win key cannot normally be used for shortcuts inside Word for Windows (it really should be available).

I use this macro mostly in novel notes where I have long outlines, and I want to quickly append notes as I’m developing ideas. It's also nice sometimes in my novel documents since I create a running outline as I write.

This version works with the standard heading styles Heading 1 – 9 as well as any paragraph styles derived from them like Act, Chapter, Scene, or Subscene. It should handle almost all special cases. In testing, the only exception was an empty document which seemed superfluous to include in a presentable macro.

Improvements?

This macro is robust and almost comprehensive for its targeted task, but we could improve a couple things. Unfortunately, both are outside the scope of this article.

Add an undo record

The macro makes three changes to the document: adding a new paragraph, moving the insertion point to it, and changing its paragraph style. It would be nice to use an undo record, so all changes are intuitively undone as a unit if we change our mind.

However, be extra careful when implementing undo records since they can cause issues. I've even lost some novel text because I did not properly end an undo record. They are nice and even recommended for the most intuitive macros. Triple check any potential errors that could short circuit a macro and prevent an undo record properly closing.

Heading overextensions

The heading level bookmark used to identify the heading range will span all heading content by default. This includes any subordinate headings and their content. Normally, this is a positive effect, but it works against the most intuitive behavior in a particular case for this macro.

Give me a second to explain.

If it is used in the top portion of a higher-level heading, the new empty paragraph will be inserted at the very bottom below all of the heading content. That is, it will position the new paragraph after the lowest (in document order) subordinate heading. This isn't an error, but it's also not quite intuitive, at least to me.

This is the only downside to using the \HeadingLevel bookmark to identify the heading range as opposed to doing so with the appropriate GoTo methods.

The problem is we have limited VBA tools available to work natively with heading ranges. We would need to create our own tools to do the job well without resorting to a monster macro. As a result, adding this feature is a major extension of the base macro with more limited use cases, so it will only be considered with significant member interest.

Affiliate Links

If you're interested in using Word or another tool related to the article, check out these affiliate links. I may make a small commission if you purchase when using them, but there is no increase in cost for you, and it helps to support this site and associated content.

I've been using Microsoft for Business for commercial use (that's us writers) on one of the lower pricing tiers for years. I get to use my macros, have online storage, and don't have to worry about software updates.