Some macros can be reimagined to incorporate additional functionality based on conditions in the document when the user runs them. This makes them more useful without needing multiple variations of the same macro concept. This version of a previous macro extends the implementation to conveniently delete the current paragraph or multiple paragraphs at once depending on the initial selection. A brief introduction to conditional statements and the Selection in VBA is also included as part of the lesson.
Thanks for your interest
This content is part of a paid plan.
Delete multiple paragraphs
Some macro ideas may be naturally extended to apply to a broader set of use cases. The previous Delete current paragraph macro worked as its name implies with the current paragraph at the editing point, but there is no reason to restrict it to a single paragraph. Why not let the macro detect the number of selected paragraphs and act appropriately?
One might ask, "what's wrong with the Delete key"? But we're making the process easier by allowing the user to make a faster selection.
The initial solution works through a natural logical process before simplifying the macro using a more refined knowledge of VBA in Word, so skip ahead if you just want the more elegant result.
Original delete paragraph macro
The original macro to delete the current paragraph was:
This macro worked regardless of whether the paragraph was selected. It is already a quick and practical macro, but we can make it better.
Quick concept review
See the previous article's explanation of the related concepts if you want a more details, but let's do a quick review of the single-line macro command.
What is a comment?
VBA ignores the first line since the text is preceded by a single quote "comment character." These are important for us humans, so we can more easily remember what we were thinking at a later date.
What is the Selection?
A selection (lowercase "s") in a Word document is a sequence of spanned content including text, tables, drawing objects, etc. We will focus almost exclusively on text selections throughout our articles given our goal of helping authors write and edit faster.
The Selection (capital "S") in VBA spans that same document content as expected, but it also includes additional information to properly reference and control it in a macro. The data are called "properties," and any actions we can take on that data are called "methods." If no text is selected, then VBA basically considers the Selection to be positioned at the insertion point in the document (the blinking I-bar waiting for typed text not the mouse pointer). It's actually a little more complicated, but we'll work based on that understanding for now.
Selection Paragraphs
The Selection has a collection of Paragraphs included in the spanned text. In the above macro, we referred to the First Paragraph of the collection since that was the current paragraph in the document.
Referencing data or actions?
In VBA, we reference data or actions associated with a given variable or "object" using a dot "." This command tells VBA we're specifically referring to the collection of all Paragraphs in the Selection. Then First refers to the Paragraphs collection and so forth for each successive dot.
Delete the current paragraph
A general document Range in VBA has a Delete action, so we finally refer to the Range of the first Paragraph and then Delete it. Importantly, this approach works even without the user selecting the paragraph or if only part of the paragraph is selected.
Extend the delete paragraph macro
In our extension, we still want the macro to delete the current paragraph just like the original version, but we also want it to delete multiple paragraphs if a selection extends over more than one.
What can we do better?
If we force the user to select all the paragraph contents, there would be no difference between this macro and just hitting the delete key after selecting the text. Our macro needs to make things easier not just insert a middleman macro that adds nothing to the process.
The original macro did not require the paragraph to be selected before deleting it, so let's lean into that practical simplification for multiple paragraphs. The user just makes a quick selection including at least some of each paragraph to be deleted and taps the macro shortcut before moving on with their work. Such a "sloppy" selection is easier and faster to do.
How many paragraphs?
Now we have to get to some VBA specifics to implement the macro. How can we check the number of selected paragraphs when the macro is run?
Let's take a detour with a direct logical route, but in the end, we'll "realize" we can skip some steps since part of the final macro actually works for any number of paragraphs. Skip ahead if you just want the result.
Decisions, decisions (conditional statements)
We need a way to make a decision in the macro based on some condition in the document. In VBA (and most other languages), a "conditional statement" uses steps something like "If ... then ... do some optional steps." More types of conditional statements exist, but an If statement is the most common one.
What is a condition?
What in the world is a "condition" for our If statement?
Many types of conditions exist, but in the end, they need to give us a "Yes" or "No" answer which VBA represents as "True" or "False" value. If the condition is True, we perform the necessary optional steps in the macro. If not, we skip the optional steps. The basic structure of the statement is:
In English, a few example conditions include:
- Are these two numbers equal?
- Is the Selection empty?
- Are more than five words in the Selection?
- Is this sentence at the end of a paragraph?
Of course, we need to work out the VBA equivalent for each one, but we find a specific question we need answered because the macro steps differ based on the contents of the document.
How does it work?
The command works exactly how it reads. VBA checks SomeCondition to see if it is True. If so, then it runs the optional steps inside the statement. Otherwise, it skips the conditional steps and continues with any commands placed after the end of the statement. If you want more details, see our article for a brief introduction to conditional statements in VBA.
Most people also indent the contents of the conditional statement to clearly identify which commands are inside or outside, but VBA does not care.
End the conditional statement
We need to clearly tell VBA where the If statement steps end. We can't be ambiguous about it, or VBA will get confused and complain which is annoying. Fortunately, it's obvious in VBA. End the conditional steps by literally including "End If" on its own line after the last optional step. A shorthand notation exists where the End If is omitted if the whole statement is on one line, but in the interest of clarity, it should only be used for simple statements.
What is the conditional statement?
The easiest way of checking for multiple paragraphs in the Selection is to just see if there is one paragraph. If there is one, we delete it like before in the original macro (all the way up top). If not, we know multiple paragraphs exist in the Selection which we will address below.
This is called "pseudo-code" by the way. It won't actually run in a macro. We're just trying to get the steps down in our mind.
What is the number of paragraphs in the Selection?
Ahhh ... now for the details. How can we detect how many paragraphs are in the Selection?
The Paragraphs collection has a Count property which stores how many paragraphs are included which is exactly the information we need. We reference it using the Paragraphs collection just like we did before. Specifically, Selection.Paragraphs refers to the collection, and then we reference the Count data (property) which looks like:
Now what do we do with the paragraph count?
Checking whether two values are equal?
In VBA, we check whether one number is equal to another using an equals = sign.
Unfortunately, in VBA this also looks like assigning the Number2 value to the Number1 variable; but when used in a conditional statement, VBA interprets it as a True or False (Boolean) value. This notational ambiguity is unfortunate (some languages use a double equals == sign in the conditional context to be clearer), but we're stuck with it in VBA.
Paragraph count condition
Now we need to know if the number of paragraphs in the Selection is 1. The condition is:
A Selection in Word VBA cannot have zero paragraphs since the current paragraph counts even if no characters are selected or even if the paragraph is empty.
Paragraph count conditional statement
Putting the ideas together for the single paragraph case, the result in VBA is:
Finally, we've recreated the original macro for a single paragraph. This macro snippet checks if there is one paragraph in the Selection. If so, it deletes the paragraph. If more than one paragraph is in the Selection, then it will skip the delete step and proceed with any other steps after the End If line.
Deleting multiple paragraphs
The second case handles multiple paragraphs in the selection. The macro should delete all of the selected paragraphs even if the selection does not include the full paragraph contents.

Allowing partial paragraph selections is convenient, so we don't need to be as detailed with our selections to properly use the macro. If we have to remember any special steps, we're much less likely to use the macro. Moreover, if we required users to select the entire paragraphs, no more and no less, before running the macro, they could just press the Delete key instead. Our macro would be moot.
Word VBA includes a paragraph in the Paragraphs collection even if it only spans a single character of the additional paragraph, so we can easily refer to all full paragraph contents related to the selection.
Else condition
We need a way to tell the above conditional statement to do one thing if the condition is True; otherwise do something else. That's almost exactly how we write it. We include an Else part in between the If and the End if separating the respective steps.
In this conditional statement, either the True or the False steps are run but not both. The Else part is optional, so we only include it when we have steps to run with a False condition.
What do we want to do exactly?
Fortunately, our requirements amount to checking for one condition (a single paragraph) and lumping everything else into the second condition (multiple paragraphs). Now that we have two conditions, we need to decide what to do in each case.
One paragraph?
If only part of one paragraph is included in the selection, then delete it like normal. This is the True portion of the conditional statement we handled above.
Multiple Paragraphs?
Even an empty selection has at least one paragraph in its Paragraphs collection. Thus, if the paragraphs count is bigger than one (condition is False), at least two paragraphs must be in the Selection. If so, delete the selected paragraphs.
This is where we have to think a little more carefully. What if the user didn't select all of the first or last paragraph?
Presumably, the middle paragraphs have no way to be partially selected since we're ignoring any non-contiguous selections in Word (VBA does not like them). The problem seems to lie with the first and last paragraphs.
VBA makes this kind of stuff easier than most other programming languages, so it sounds harder than it is once you get the concepts. To answer the question, we have to dig a little deeper into understanding what a selection is in Word and how VBA sees it.
How can we select all the paragraph content?
In the original macro all the way up top, we got away with not selecting the current (first) paragraph since the Selection.Paragraphs.First.Range part of the command referred to the entirety of the first paragraph contents. Now we don't have that luxury. We need to include all contents of the first and last paragraphs using steps in the macro.
Manual analogies?
One way to work out the steps in VBA is to imagine doing it manually in Word. However, this approach is counterproductive for many macros since the VBA steps do not always coincide with the manual steps. VBA just stores and uses the information a little differently than our fingers work inside Word. This is also why recording macros can sometimes lead to clunky (and bloated) macros. Unfortunately, this macro is one of those where the manual steps in a document are not quite right in VBA. It could be done, but the steps are just a little awkward to replicate in VBA.
What's the better VBA way?
We need the Selection to span the entirety of all paragraphs to be deleted. We extend the beginning of the existing Selection backward in the document to the start of the first paragraph. Then we extend the end of the Selection forward in the document to the end of the last paragraph. Everything in the middle remains selected.
More on the Selection in VBA
A Selection (actually any general "Range" in a Word document) is basically a starting point in the document and an ending point in the document. These values are stored as the Start and End properties, respectively. They are literally character positions in the document, but we don't have to worry about that detail to solve our current problem.
You might guess: "Okay, just refer to the Selection.Start and Selection.End positions then ..."
Just hold on.
The catch is Selection.Start currently corresponds to the position at the beginning of the document selection which is not necessarily the same as the beginning of the first paragraph of the Selection. A similar argument applies to the Selection.End position and ending position of the last paragraph.
Get the start of the first paragraph
We refer to the first paragraph of the Selection just like we did in the original macro, but now we want its Start position.
We again needed the range of the paragraph since a VBA Paragraph does not include a Start property on its own.
Now we have the Start position of the paragraph, but what do we do with it? How can we set the start of the selection to the start of the first paragraph?
Simple Assignments in VBA
That brings us to assignments. In general, we can set one simple variable value to another using just an equals = sign using an expression like:
In VBA, this statement assigns the value 1 to the variable x.
Assign the Start position of the Selection
We do the same thing with the Start of the Selection and the Start of the first paragraph. Specifically, we assign the Start position of the Selection the value of the Start position of the first paragraph.
This command directly (in VBA) moved the Start position backward in the document (without changing the End position) thus extending the document selection in that direction.
Assign the End position of the Selection
Now repeat all the same concepts for the end of the last paragraph. One caveat is we get the Last paragraph in the Selection using Selection.Paragraphs.Last just like we did with the first paragraph in the Selection above.
Now we assign the End position of the last paragraph's range to the End of the Selection.
This command moved the End position forward in the document without changing the Start position, so our Selection now spans all paragraphs even partially included in the original selection.
Delete the extended Selection
Now that we have the Selection Start and End positions set correctly, we can just delete what we've selected.
Yep, that's all. We've done the hard work already.
Putting it together
Combining these last two statements with the delete command, we can now delete multiple selected paragraphs when the macro is run.
Recall these steps were to be run for multiple paragraphs inside the "Else" part of the above If statement.
Gotchas
It's a good habit to take a moment to consider assumptions that could return to bite you after you walk away. It's better to figure it out now than to "discover" a problem when you're working on your novel!
What if the selection already includes the full paragraph contents?
Yep, we should at least consider these things. In this macro, if the Selection's Start position is already at the paragraph's Start position, then nothing will change.
Why?
We're just setting the former value equal to the latter, but they two positions are already equal, so nothing changes. A similar argument applies to the end of the last paragraph. The macro will work as expected, so we can finish the macro.
Delete paragraphs macro (naïve version)
Putting it all together, we have our final macro to delete any number of paragraphs in the document.
Since the macro is more complicated than the original, I included multiple comments (the description text after the single quotes) clarifying the intention for each group of steps. Comments are ignored by VBA, but they will help later if we need to make any modifications.
I assigned my version of this macro to Command+Shift+Delete in Word for Mac or Control+Shift+Delete in Windows.
Possible improvements
What could we do better?
Fix Selection manipulation issues?
Adjusting the Selection multiple times during a macro could cause text to "flicker" as the macro runs (more on the Selection), so we could use a document Range variable instead (see introductory article on ranges for more information) instead of manipulating the Selection directly. We haven't covered Ranges in any detail yet; and changes to the Selection in this macro occur so fast, it is likely not even noticeable in practice.
Couldn't we just extend the Start or End position of the Selection?
Yeah … and we will sometimes, but we need to be careful.
The most direct selection extension method uses the Selection's StartOf method, so we do not unintentionally extend the selection to the previous paragraph if the user has actually started the selection at the beginning of the paragraph.
We'll get into the details of such move or extend commands later. The approaches are essentially equivalent, so choosing between this method and the above is just a preference. If you're tracking the articles sequentially, the solution below just follows more easily from what we've learned so far.
Cut or Copy versions?
We could also trivially modify the macro to cut or copy the paragraph contents to the clipboard by replacing the Delete action (method) with Cut or Copy. I prefer a complete series of macros, when possible, especially when they are such trivial but nevertheless useful extensions. I assigned these macros to Command+Shift+X and Command+Shift+C, respectively, in Word for Mac substituting Control for Command in Word for Windows.
Simplification …
More importantly for this macro, it has some unnecessary steps which we solve with a more elegant version below.
Make it cleaner and more efficient
Huh, the article isn't over yet?
Well … not if you like clean macros. Look back through the steps for multiple paragraphs above. We want to delete one or more paragraphs. If the macro runs with an initial selection across the paragraphs, it follows these rough steps:
- Move the start of the selection back to the beginning of the first paragraph.
- Move the end of the selection to the end of the last paragraph.
- Delete the extended selection.
But what if the initial selection were fully contained inside a single paragraph? Would it still work?
- In step 1, moving the Start of the Selection for the first paragraph is the same thing, so no problem there.
- In step 2, the first paragraph is also the last when deleting a single paragraph, so moving the end of the selection to the end of the last paragraph works just fine also.
Moreover, it works correctly even if no initial selection exists because that just means the Start and End positions are initially the same, and the selection extensions aren't directly related anyhow other than both occur with the Selection.
Hmmm.
Clean your room
So what? We got a few extra steps. It works, right?
I suppose that's one way to look at it. We're not usually concerned with hyper efficiency in our macros because most of them run literally in the blink of an eye. However, jumbly or superfluous steps are off-putting and sometimes confusing.
More importantly, cleaning up the macro takes another step on our journey of thinking a little more like VBA, when necessary, rather than just hacking macros together along the way. Don't worry, we can still put our writing and editing hat back on after the macro is finished.
Simplified but fully functional macro
We don't need the conditional statement stuff since the steps for multiple paragraphs also work on a single paragraph. This is not always the case, but it allows us to strip out the extraneous conditional steps. Here is the simplified version:
It gets the same job done with fewer steps, but getting this right the first time would probably have required a little more practice thinking like VBA in Word. That's why we went the long way around the block above. This version also has a teensy efficiency boost, but we would never notice the difference in practice.
We still need to be a little careful when extending macros in the sense that the extensions need to make sense as well as be intuitive and useful, but everything is consistent here. The macro properly works for any number of paragraphs whether or not there is a selection.