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

Layout Word windows

Word • Macros • Display
Peter Ronhovde
52
min read

We create a macro to automatically layout our Word window freeing us from doing so manually. Related articles cover assigning such a macro to a Quick Launch Bar button, a keyboard shortcut, or even triggering it when the document opens. Additional comments cover various VBA issues related to the window layout.

Thanks for your interest

This content is part of a paid plan.

Automatically layout Word windows

Starting a writing or editing work session shouldn’t take more than a click or two—no dragging, resizing, or resetting the zoom. Just click a button and get to work.

Why bother?

My old writing station included three monitors. I mainly used the center and left ones to display my working manuscript, but I’d find myself resizing and moving the window for many writing or editing sessions. I might open a web browser for research for a while and then switch back to my regular work layout. Anytime I do the same thing over and over in Word, I start to think … why not let VBA help? Or actually, just let VBA do it for me.

Of course, Windows or Mac try to remember the last position of the application, but then it changes when you momentarily work on something else. It’s nice to have a macro assigned to a shortcut or a Quick Launch button to set it all back the way I like it.

Being a perfectionist is also part of my problem. I like the windows set up exactly how I want before I start working. That little sliver of screen space to the sides of the window will draw my eye, so another advantage of using a macro is being more precise with the layout.

Toy problem

Our toy problem involves setting up a novel document ready for work. More specifically, I prefer multiple smaller pages in full view on screen mimicking the format of a paper novel. I reserve some screen space for an occasional novel notes or a working outline (created as needed via an upcoming macro).

My writing setup …

Roughly speaking, I had three novel setups with two to four pages in full view. I use a two page layout mostly when I only have one monitor available (lately) but preferably more when I have at least two full screen monitors (hopefully an ultrawide soon!). Separate macros display the novel notes or running outlines as needed often on a third monitor, but the three page layout gives me some flexibility to keep everything in view on two monitors if needed.

All of this requires specific window positions, width and height, zoom amount, and some page settings. It sounds like a lot, but it’s nice when you can just pop between different layouts as you research and then move back to just editing or writing.

Warning: A storm’s a brewin

Hold onto your hats though folks ‘cause plot twists abound, but we’ll ride into town before the storm hits too hard.

Takin a gander at the clouds ahead, multiple factors affect the window scaling, and while I address one of the bigger factors in this article, at least two others can throw off the window position or size—meaning you may need to tweak the numbers manually regardless depending on your specific hardware and system settings. Still, I think it’s worth the extra effort.

Standard system snapping features

Before we get started with the details, both Windows and Mac have existing features to switch between certain standard layout options:

  • Snap windows to sections of the monitor in Windows or on a Mac. If you don’t like how the default positions work, both systems have third party applications to achieve more varied results. PowerToys is a free app in Windows, for example, and Magnet is a common paid app for Mac.
  • Windows also has standard keyboard shortcuts to move applications between monitors (Windows Command+Left or Right). Macs have some standard menu options for the same purpose which can be assigned to keyboard shortcuts through the system settings.

This article is not a review of any of these or other related features. Rather we’re creating our own detailed layout within Word. We’ll have much more specific control over the size and position of our Word windows but also other things like the screen zoom, multiple page layouts, or almost anything else Word allows. The layout can even be triggered automatically when our novel opens using the AutoOpen macro which is covered in the next article.

Macro skeleton

I’ve created layout variations for different document types including novels, outlines, and notes; but we’ll only work with a single novel layout variation today just to keep things specific. Your own working layout will vary anyhow.

Sub LayoutNovelWindow()
' Reposition the active window on the left side of a wide screen (not maximized)
' Set a zoom setting with a multipage layout
' Place Navigation Pane floating to the right

End Sub

This macro is a subroutine not a function, so it has no return value. Also, it requires no parameters which allows us to assign it to a Quick Launch bar button or a keyboard shortcut.

Unfortunately, there are enough differences between Windows and Mac for window layouts that we need two separate macros.

Sub LayoutNovelWindowMac()
' Reposition the active window on the left side of a wide screen
' Set a zoom setting with a multipage layout

End Sub

I use both systems, so I need distinct names. If you prefer a single macro that does both, we covered preprocessor directives in previous (unrelated) articles. If you’ve ever dug through a math or physics textbook, you’ve probably read something like, “We’ll leave it as an exercise to the reader …”

Ughhh, but we can only cover so much.

Relevant settings

Settings like page format and margins are much more likely to be one-time actions for a given novel, so we’re considering settings that are likely to change through regular work. What do we need to do with the active window?

  • Reposition and resize the Word window
  • Set at least two pages in the document View (more for an ultrawide screen or when spanning two monitors)
  • Set the zoom percentage
  • Position and size the Navigation Pane floating to one side of Word (Windows only)

I wish we could hide the Word ribbon by default, but VBA doesn’t give us specific control over it … arghhh.

Some issues exist with the position and size properties when Word is maximized in Windows. Moreover, Windows 11 seems to reserve, or at least fight you over, several pixels to the left, right, and bottom of the window which aggravates certain perfectionists.

Get the ActiveWindow

We need to get the window currently waiting on user input, so we can reference the various layout properties. Technically, we start with the ActiveDocument of the Application, but VBA allows some flexibility in this case.

We usually work with a single editing window, but since it is possible to open multiple windows for the same document (using View → New Window, for example), we need to refer to the active window for the current document. With this in mind, we reference the ActiveWindow property of the ActiveDocument.

Application.ActiveDocument.ActiveWindow

Shorthand ActiveWindow reference

As a shorthand notation, we can refer to many Application properties without directly using the Application object, so we can just use:

ActiveWindow

We could also define a Window object variable to use, but this is already available.

Some subtleties and issues exist regarding the differences between the Application and the ActiveWindow in terms of the position and size properties but see the Gotchas section below if you’re interested in those details.

Word window layout

What properties move the Word window?

With a Window object, we refer to the Top and Left properties to set the top-left corner of the active window.

ActiveWindow.Top
ActiveWindow.Left

These are just number values in points in Word for Windows but pixels on a Mac—

Huh?

Oh, points or pixels. Yeah, that’s a little annoying, so we gotta talk about points and the inconsistent units between Word for Mac and Windows.

Unfortunately, Windows 11 also seems to override some window position and size settings near monitor edges but see the gotchas toward the end for more about this.

Position properties

Zero is the top or left of your main screen not the bottom-left like you might expect from plots in mathematics class.

ActiveWindow.Top = 0
ActiveWindow.Left = 0

Aside from zero values, it can be frustrating to exactly position a window with these properties since we’re probably more familiar with pixels than points, so we’ll determine a monitor-specific conversion factor for the position assignments.

Points unit (Windows only)

Points is a literal distance unit. Yeah, it’s the same point unit from font sizes, and it is defined as 1/72 of an inch in desktop publishing (historically, some variation existed in print).

Pixels unit (Mac only)

Despite the online documentation, my testing over various monitors indicates these properties in Word for Mac VBA use pixels not points. This is more convenient since we’re already used to pixels. We can easily look up the screen resolution for our monitor rather than needing to dig into a typographical conversion factor, but some consistency or at least a note in the documentation would have been nice.

Size properties

What properties resize a window?

Instead of setting the bottom-right corner to specify the size of our Word window (defining opposite corners of an on-screen rectangle), we set the window’s Height and Width properties.

ActiveWindow.Height
ActiveWindow.Width

The effect of the Height and Width properties is related to your pixel size (often quoted as pixels or dots per inch), current screen resolution even if your monitor supports higher resolutions, as well as the system screen scaling if using Windows.

Usable height and width

In principle, we could take advantage of two tempting generalized values: the UsableHeight and UsableWidth properties, so no worries, right?

ActiveWindow.Height = ActiveWindow.UsableHeight ' Inconsistent?
ActiveWindow.Width = ActiveWindow.UsableWidth

Well, about that …

Yeah, sounds like a quick warning shot into the big sky and put the bad guys in jail before dinner gets cold but not really. At least, they don’t seem to work as expected, and they’re inconsistent on Mac at best. We get no errors, but they’re ignored, or any effect is sporadic.

Vertical space adjustments

Unless you work with the taskbar autohiding itself, it also takes up screen space. My system shows it as 72 pixels high, but some Windows 11 systems supposedly allow up to three different sizes (unclear if the settings are still available with recent system updates). The taskbar sizing is also affected by the screen scaling in Windows display settings. On a Mac, the corresponding “Dock” takes up a variable amount of vertical height, and the menu occupies 24 or 48 pixels on the top of the screen depending on the type of display.

Points and pixels (Windows only)

It’s easier to set the properties in pixels, but the VBA documentation states the various window position and size properties use points. Yep, like the font size points if you live in computer land.

Points are a typographical distance unit representing the real size of something on a page, but the connection to print is a little fuzzy since it varied some historically. The supposed advantage of using points is it is an actual distance unit as opposed to a relative one.

In an operating system, we can set different screen resolution settings as well as a screen scaling in Windows for the overall display. In Word specifically, we also have a zoom percentage for the document window, so the correlation isn’t exact presumably unless the other scales are set to 100%.

On the hardware side, a monitor’s resolution in horizontal by vertical pixel dimensions is only related to a real distance. Different screen resolutions can exist with different monitor sizes due to different pixel sizes (and also pixel pitch or spacing but we won’t get into that topic much).

The notion of pixels is more practical for modern computer users when thinking about the position and size of windows on the screen, so we need to connect points to pixels before we can provide a meaningful number to the size properties.

Understanding pixels

Roughly speaking, larger pixels make the image grainier, and smaller pixels smooth out edges to our eyes. The pixel size combined with the pixel spacing for your monitor relates its pixel dimensions to a real distance unit. It’s kind of like a pixel density (per unit length) for your monitor. A relatively standard measurement for pixel size is pixels per inch (PPI), but it’s also often given in pixels per millimeter. We’ll stick with pixels per inch since a point is defined in terms of points per inch in desktop publishing.

Most modern monitors look decent from a human’s perspective unless you’re doing graphic design or are just a gaming perfectionist. We just want to place a window on the screen properly using pixels not points. Determining a conversion factor between them makes this more convenient.

Unfortunately, I can’t determine your monitor’s pixel size from my side of the screen, but an internet search or two should reveal the pixel size for your monitor model. Unfortunately, some online references don’t provide the information as readily as the screen resolution, but it is usually available with a little digging.

Getting the points to pixel scale factor

The conversion is simple, but unfortunately, all the gotchas ahead makes for a bumpy ride. We basically need two numbers for the scale factor calculation.

  • What is a point in real screen distance? This is already defined in desktop publishing as 72 points per inch.
  • What is your pixel size for your monitor in pixels per inch?

Historically, a typographical point varied somewhere around a hundredth of an inch, but modern desktop publishing has defined the value to be 72 points per inch. Essentially, we divide the 72 points per inch definition by your monitor’s pixel size in pixels per inch.

Let’s step through the calculation.

Define some convenient constants

We first define a couple constants to make the calculation easier to read.

Const PointsPerInch As Double = 72 ' Actual size of a point unit

Then we need the pixel size information for your monitor in pixels per inch.

' Insert the pixels per inch for your monitor
Const PixelsPerInch As Double = 96 ' PPI for my old monitor

The number 96 is just the pixel size for an older monitor that I still use. Defining separate constants like this isn’t necessary. We’re just trying to be clear, but it does avoid a weird VBA calculation gotcha (see below).

Variable declaration review

We’ve previously declared variables using Dim like so where the data type is specified “As …” after the variable name.

Dim SomeVariable As Double ' Variable value can change

Technically, we don’t have to define a variable in VBA (unless you use Option Explicit) since VBA will just create as we ride, but it’s probably a good idea. A simple variable spelling error could cause trouble later when VBA thinks you just mean for it to create another variable. Why spend an hour squashing a subtle bug when VBA could find it in a millisecond?

For VBA variables, we need to manually assign a value as a separate step after declaring the variable (regular Visual Basic allows a shorthand notation all on one line).

SomeVariable = 0.0 ' Assign a value to the variable

A variable value can change over the course of a macro.

Using Const-ants

We haven’t used Const much on this site, but it works much like Dim except we’re telling VBA we’re not going to change the value. VBA will then require it of us.

Const SomeConstant As Double ' Fixed constant (not quite done)

Clearly Const is just an abbreviation for Constant much like Dim is an abbreviation for Dimension. Not sure how much omitting three letters for Constant really helps us, but we just exchange Dim for Const in the declaration. We’ll get to the Double number type below.

We can’t assign a value to a constant after defining it … because its value is fixed when it’s declared. Thus, we somehow need to assign the value when we create the constant. The notation is similar to defining default values for Optional parameters in subroutines or functions. We just append an “=” with a relevant fixed value after the data type.

Const SomeConstant As Double = 0.0 ' Fixed constant value

Why VBA doesn’t allow this shorthand for initial variable values is perplexing since it clearly works for Constants.

We can also perform calculations to determine new constants using previously defined constants.

' Define a constant based on another constant
Const AnotherConstant As Double = SomeConstant * 2.0
Why use a constant?

For anything but the simplest or most common fixed values, a constant with a name is easier to read. It’s better to be specific and clear when possible, and if the value is reused anywhere else in the macro, you only need to define it once. If you intend for it to never change, VBA will notify you if you forget and try to change it later since your thinking was wrong on at least one of the occasions. A few other more technical benefits of Const-ant values exist, but we’ll leave those alone here.

What is a Double number type?

Regular Visual Basic allows a “Decimal” number type which would be clearer here, but it’s not available in VBA without some shenanigans. It’s a little odd because VBA usually strives to be as easy as possible to read and use.

We can’t use a counting number type such as a Long or Integer for our pixels to points conversion factor because with modern monitors it will almost certainly be less than one. Such numbers are generally stored as “floating point” numbers in computer speak. In modern programming, this is usually done with a “Double” type meaning it’s twice as big as a Single number type …

See, easy peasy—

Oh, not really?

Hmmm.

Remember your scientific notation stuff from science class? It’s a similar idea in programming languages. A decimal number (not talking about the Decimal type Visual Basic allows) has to be stored differently in computers than counting numbers. The decimal point is allowed to “float” meaning VBA stores and calculates the main number (mantissa) and the power of ten separately (as part of a larger composite number thingy in memory) and adjusts them as needed for consistency when a variable value changes.

VBA calls its version of this original floating point number type Single, but some languages call it “float”. Many programmers with more demanding needs found its lack of accuracy (number of reliable digits) limiting. It became more common to use a larger number, literally larger in memory usage but also in the number of accurate digits, which ended up being called a Double type in many languages.

We’re not worried about the details of the data storage more than the above commentary. Either number type stores more accurate numbers than we’ll need for this macro, so we’ll just use the more common Double number type.

Conversion factor

Our conversion factor for points to monitor pixels is:

' Pixel to points scale factor for your monitor
Const PointsPerPixel As Double = PointsPerInch / PixelsPerInch

This works because both values on the right are also Const-ants which were defined earlier. Thinking about the units, the inverse inches cancel out leaving us with units of points per pixel which is exactly what we need.

Doing the calculation explicitly avoids a weird constants feature bug (see Gotchas below if you want the details). As a reminder, Word for Mac VBA seems to veer from the official documentation and use pixel values directly for the position and size property assignments.

More concise version

If you prefer to condense this to one line, just use the plain numbers with some explanation.

' Point to pixels scale factor for a monitor with 96 pixels per inch
Const PointsPerPixel As Double = 72 / 96
Using the scale factor

How do we use the conversion factor?

This example calculation converts 3840 pixels to points and assigns it to the Width property of the ActiveWindow.

' Example pixels to points conversion
ActiveWindow.Width = 3840 * PointsPerPixel

That’s it.

Now we can presumably give our value as 3840 pixels saving us a few brain cycles … kind of. At least two other scale factor issues exist that are more difficult to pin down, so you may still need to tinker with the numbers to get exactly what you want.

Now repeat for each relevant position or size property.

ActiveWindow.Height = 1128 * PointsPerPixel
ActiveWindow.Top = 0 ' Scale factor is redundant for zero
ActiveWindow.Left = -1920 * PointsPerPixel

In this toy example, all three monitors have a resolution of 1920 by 1200. I’m using my middle one as the main monitor, so I set the Left side of the writing window to the left side of the left monitor—thus the -1920 pixel position. The width of 3840 pixels spans two monitors. The height is 1128 pixels to allow for a 72 pixel tall taskbar in Windows.

Double conversion

The intermediate value 3840 * PointsPerPixel is a Double floating point value internally to Visual Basic for Applications since PointsPerPixel has a Double number type. Since the Width property is a Long number type, VBA automatically rounds the Double number to the closest Long number value before storing it.

Zoom settings

How can we adjust the zoom settings?

The most obvious zoom property is the percentage scale factor for the current active window view. Any Word Window has a View property which we just reference as normal.

ActiveWindow.View

We then reference its Zoom property to set the various zoom settings.

ActiveWindow.View.Zoom

Zoom pages

I like having multiple pages in view, so I first set the PageColumns and PageRows for the view.

ActiveWindow.View.Zoom.PageColumns = 2
ActiveWindow.View.Zoom.PageRows = 1

PageColumns is literally how many pages are displayed across the window, and PageRows is how many rows are displayed vertically. Of course, not all combinations are valid. I tend to use a 1 row by 2 to 4 columns depending on how wide my monitor is at the time. Each property is just a counting number as a Long number type, so we assign an appropriate value using an equals = sign.

Unfortunately, the page row and column settings need to be assigned before the Zoom Percentage, or Word will reset the percentage to a value it thinks is more appropriate for the number of displayed pages. It kind of makes sense since Word likes to display full pages when these properties are set, but it's a tad annoying. I suppose the work around is simple enough.

Zoom percentage

The Zoom Percentage value is displayed next to the Zoom slider usually on the status bar at the bottom-right of the Word window. It’s just a counting number as a Long value, so we again assign a value with an equals = sign. I tend to set it around 180% of normal view size.

ActiveWindow.View.Zoom.Percentage = 180

Using With is nicer

We’re referencing the ActiveWindow for most properties, so it’s nice to incorporate another shorthand notation using a With statement. The basic command is:

With SomeObject.SomeProperty
' Refer to any properties or methods of SomeObject.SomeProperty ...
End With

With With (how many times have you written that with correct grammar?), the macro is more concise. With statements are also ever so slightly a teensy weensy bit faster, but you’d never notice the difference in a Word macro.

Collected layout properties

Collecting our various layout properties so far, we have the window position and size:

ActiveWindow.Top = 0 ' Scale factor is redundant for zero
ActiveWindow.Left = -1920 * PointsPerPixel
ActiveWindow.Width = 3840 * PointsPerPixel
ActiveWindow.Height = 1128 * PointsPerPixel

Then we have various view zoom properties.

ActiveWindow.View.Zoom.PageColumns = 2
ActiveWindow.View.Zoom.PageRows = 1
ActiveWindow.View.Zoom.Percentage = 180

Revised layout properties using With

Our reference object is the ActiveWindow of the Application.

With Application.ActiveDocument.ActiveWindow
' Refer to any properties or methods of the ActiveWindow
End With

Now simplify the collected properties using the With statement by omitting any reference to ActiveWindow (just start with a dot).

' Set various layout properties of the ActiveWindow
With Application.ActiveDocument.ActiveWindow
' Set the size and position of the ActiveWindow
.Top = 0 ' No scale factor for zero
.Left = -1920 * PointsPerPixel
.Width = 3840 * PointsPerPixel
.Height = 1128 * PointsPerPixel

' Adjust zoom and how many pages are displayed
.View.Zoom.PageColumns = 2
.View.Zoom.PageRows = 1
.View.Zoom.Percentage = 180 ' Must set after pages
End With

This looks similar but a little cleaner.

Alternative with two With statements

The second batch of Zoom properties are again all similar, so we could instead use two with statements.

' Set position and size of the ActiveWindow
With Application.ActiveDocument.ActiveWindow
.Top = 0 ' No scale factor for zero
.Left = -1920 * PointsPerPixel
.Width = 3840 * PointsPerPixel
.Height = 1128 * PointsPerPixel
End With

Then add a separate With statement for the View Zoom properties.

' Adjust zoom and how many pages are displayed
With Application.ActiveDocument.ActiveWindow.View.Zoom
.PageColumns = 2
.PageRows = 1
.Percentage = 180 ' Must set after pages
End With

It’s just your preference on which you think looks tidier.

Adjusting Navigation Pane layout (Windows only)

In Word for Windows, I like to automatically position the Navigation pane in a convenient place. Unfortunately, manipulating extra panes in Word for Mac VBA doesn’t seem to work. Even in Windows, it’s clunky.

Why use the Navigation Pane?

The Navigation Pane helps keep track of a running outline if you happen add chapter and scene headings as you write (helps me keep track of my story as it develops). In Windows, we can also drag and drop headings along with the content inside the Navigation Pane. It’s not perfect (occasional formatting issues pop up), but I often reorder scenes and subscenes this way.

Command bars …

The Navigation Pane is an example of a “command bar” in Word, but even that is an older concept in Word VBA (see an overview of the Office Fluent ribbon a.k.a. the “ribbon”). I don’t think of the Navigation Pane as a toolbar- or menu-like object in Word, but we can access it through the CommandBars collection of the Application using its plain text name “Navigation”.

Application.CommandBars("Navigation") ' Access Navigation Pane

Sounds okay so far … yeah, you hear it coming.

Danger: Storm's a blowin in!

Unfortunately, it’s a little confusing since the Navigation “Pane” is kind of not an actual Pane object with a capital “P” in VBA nor a TaskPane (the constant is not in the WdTaskPanes enumeration at least as of October 2024). A Word Pane is a second, in-window display of the document contents or other information. A TaskPane includes the Research and Thesaurus panes, for example, which seems to match the concept of the Navigation Pane …

Just hold on though.

I say kind of because toggling the Navigation Pane visibility through the ribbon does not increment the TaskPanes.Count property. However, opening the Navigation Pane open seems to increment the Panes.Count property (the number of window panes currently open), but we can’t seem to do anything with it through that collection …

Whoa … I’m confused.

Yep, sorry about all that. It’s a little frustrating but outside my control.

The name or object type clashes for the various overlapping Word concepts in VBA probably developed over time as extra features were added and/or changed in Word and in VBA. The documentation is terse at best, so we kind of just have to ride into the driving rain and get our work done anyhow.

Does not work on Mac?

It gets even worse because we can’t seem to access it through VBA in Word for Mac. Referring to it doesn’t give us an error, but it doesn’t do anything even something as simple as making it Visible or not.

Application.CommandBars("Navigation").Visible = True ' Does not work on Mac?

Positioning the Navigation Pane

Now that we’ve given the caveats, we’ll start with a With statement this time.

With Application.CommandBars("Navigation")
' Adjust Navigation Pane properties ...
End With
Floating pane

The various panes can float as separate mini-windows or be docked inside Word to either side. The relevant property is the Position. This isn’t asking for a location on the screen but a docking style. We need a constant from the bar position MsoBarPosition enumeration table. The main ones for us with the Navigation Pane are msoBarFloating or the docked pane constants msoBarRight or msoBarLeft, obviously attached to the Right or Left side of the Word window, respectively.

.Position = msoBarFloating

In my multimonitor writing setups, I tend to prefer a wider floating Navigation Pane to one side of my Word window. When writing on a single screen, I usually prefer it docked on the left side.

Visibility

If we always want the Navigation Pane visible, we set the Visible property to True, but it doesn’t hurt to include the step if it is already visible.

.Visible = True
Position and size properties

For a floating Navigation Pane, we want to adjust several similar properties to the window: Left, Top, Width, Height.

.Top = 0
.Left = 2000
.Width = 420
.Height = 1160

Each of these properties are needed in pixels not points like the same properties used by the Word window!

Arghhh.

Collected steps

Putting it all together for a floating Navigation Pane, we have:

With Application.CommandBars("Navigation")
' Setup a floating Navigation Pane
.Position = msoBarFloating
.Visible = True

' Set position and size properties of Navigation Pane
' Except for Width, an error occurs on assignments if pane is docked
.Top = 0
.Left = 2000
.Width = 420
.Height = 1160
End With
Changes for docked pane

Three of the position (not capital “P”) and size properties will cause an error if the pane is docked inside the Word window, so we need to be careful. Specifically for a docked setup, we omit the Top, Left, and Height properties. Docking to the Left is probably more common.

With Application.CommandBars("Navigation")
.Position = msoBarLeft ' Dock on left side of Word window
.Visible = True
.Width = 280
End With

In some wide screen setups, I’ve included the Thesaurus and Research panes for testing, but I found I didn’t use them much.

Gotchas

We’ve got a wagon load of gotchas here. A few we can correct. Some we need to understand and work around them like a big sloppy mud pit in the middle of the trail, but others just are, and we must deal with them as is.

Many of these issues may be relatively safely ignored if you prefer to skip ahead to the final macros. The exceptions are the no open documents check and being aware of Integer multiplication limits in VBA if you prefer to use explicit numbers in your macros.

Normal window state (Windows only)

Trying to reposition or resize a maximized window in Word for Windows will cause an error. In principle, we could restore a normal state just before carrying out the actions.

' Works for runtime, but not on startup (ignored on Mac)
Application.WindowState = wdWindowStateNormal

The wdWindowStateNormal is from the WdWindowState enumeration table.

Does not work when opening a document

Unfortunately, this only works when the macro is run with Word already open. It may not work reliably when launching the application automatically upon opening a document (see next article on the Word AutoOpen macro). A word around could be setup to restore the normal window state when closing the document, but we won't ride that trail.

Trouble in Word for Mac

Mac doesn’t seem to care if this line is included if the window is in a normal state already, but it seems to cause an error if the window is maximized even if Word is already open.

Ughhh. One more thing to avoid.

Windows position and size overrides?

I prefer a full screen view without a maximized window, but Windows 11 seems to tweak some window positions and sizes near the left or right edge of the screen. It likes to reserve a sliver of empty space on two or three sides around the window. I even turned off the default window snapping behavior in the Windows settings, but the positioning restriction persisted. I have not tested all variations for all details, but even when I tried to cheat it using negative or oversized offsets, it was still finicky enough that it’s annoying to position a window to the exact pixel near the left or right edge of the screen.

I don’t recall this being a problem in versions of Windows past, but I eventually cried “Uncle” (if you’re familiar with the southern term for confrontational acquiescence) and decided to just deal with it.

Application versus Window position and size properties (Mac issue)

In principle, the Application’s position or size properties refer to exactly what it says—the position or size of the overall application window. Most of the time, we’re interested in positioning the overall application rather than the document space inside the window.

Contrast that with the Window properties of the same name but with slightly different meanings. The Application properties include all the interface stuff like the title bar, status bar, the ribbon, and the menu; but the Window stuff is supposed to refer to just the document space. That is, the Window’s Height and Width properties technically refer to the usable window space for a displayed document.

However ... in practice, they seem to be applied the same way—meaning changing the ActiveWindow settings seems to position and size the whole application window.

Hmmm. Not sure what to make of that.

Just make sure you’re using what you intended but also be aware some properties don’t work as expected, and the differences may not be documented well or at all. The vagaries are annoying to a certain scientist and programmer who also likes to write, but we gotta farm the land we got. Test your layout.

Application position and size properties (Mac issue)

My testing experiences an error when trying the Application version of the properties in Word for Mac. This is confusing because they’re in the documentation for the VBA list of properties.

' How we have referenced position and size properties so far
ActiveWindow.Top
ActiveWindow.Left
ActiveWindow.Height
ActiveWindow.Width

' These cause an error in Word for Mac despite the documentation
Application.Top
Application.Left
Application.Height
Application.Width

UsableHeight and UsableWidth properties

In principle, these properties make sense since it’s wonderful to allow Word to determine the usable window space, but in my experience, they do not seem to act intuitively—in either Word for Mac or Windows—at least from a human perspective with a real monitor in front of them.

ActiveWindow.Width = ActiveWindow.UsableWidth
ActiveWindow.Height = ActiveWindow.UsableHeight

The nice thing about these properties is they already have the expected units of points, so we supposedly don’t need a scale factor.

Zoom PageColumns and PageRows

Be careful assuming the Zoom object’s PageRows and PageColumns are always consistent with the Zoom Percentage. Sometimes they are adjusted to be internally consistent but sometimes not. In my experience, they are reset for consistency in one direction but not the other. Test.

Pane problems (Mac issue)

VBA in Word for Mac gives us almost no access to the extra working panes like Navigation or Research, but it’s actually clunky even in Windows.

Navigation Pane size and position properties (Windows only)

Unfortunately, the position and size properties for the Navigation Pane use pixels, but the corresponding properties with the ActiveWindow or Application use points …

Ummm.

Well, I suppose that’s how it is, but can we say … con-sis-ten-cy. Some more of it would be nice.

Command order matters

I suppose command order usually matters, but given how VBA doesn’t properly make all related view or zoom settings self-consistent, the order of commands is important to achieve the desired result even more so than normal.

Ribbon control is limited

Unfortunately, both Windows and Mac basically only give us a way in VBA to toggle the ribbon status between visible or hidden. The method is:

ActiveWindow.ToggleRibbon

Once my shortcuts are setup, I tend to use them and ignore the ribbon for most tasks meaning I can keep the ribbon hidden. For me, having the extra screen space is preferable when possible. To my knowledge, we cannot just set the ribbon status directly, and we can’t even detect its current status and only toggle its visibility if it has the reverse setting.

Arghhh.

It’s strange how Microsoft can give us so much control over Word in some ways but then hogties us with other tasks.

What if no document is open?

If no document is open, the ActiveWindow reference will cause the macro to crash. Normally, we would check this and sidestep an error with something like:

If ActiveWindow Is Nothing Then Exit Sub ' Does not work

If so, we would just exit the macro (subroutine or Sub for short) to avoid any problems in the following steps. Unfortunately, we’re in trouble here since referencing the ActiveWindow even to check it causes an error even before the macro can run the check. The ActiveWindow literally doesn’t exist yet even to validate it.

Just for clarity, Nothing is a value given to VBA objects that exist as variables already but haven’t been assigned to anything yet. Also, “Is” works similar to an equals = sign when comparing VBA objects.

Hmmm.

Fortunately, it shouldn’t happen often, but …

[furtive glance both ways]

Don’t tell anyone else, but if you insist, we can still catch it, and it’s not even difficult.

Documents count check

A different work around is to check how many documents are open and exit if none. Documents is a collection of exactly that within the Application (we can again omit the parent Application name). The Count property of the collection tells us how many documents are currently open, and our condition is to test whether this value is zero.

Documents.Count = 0

Then immediately exit the subroutine if no documents are open using Exit Sub.

' Make sure at least one document is open before continuing
If Documents.Count = 0 Then Exit Sub

Since this is so simple, we include it in the final macros below.

Number issues

Number conversions could cause issues in several steps.

As we’ve constructed the macro so far, no number problem exists other than an annoying VBA editor notation for floating point numbers (72#, for example, Ughhh, yuck). Move along if you don’t want any details, but at least check out the first warning if you ever plan on doing explicit number multiplication with counting numbers in VBA.

Watch out for fixed Integer multiplication!

Our current macro side steps a significant but subtle problem in VBA. Some would balk at defining two extra constants, and I understand the sentiment. This is a similar calculation that directly uses a monitor pixel position of 1440 pixels:

.Left = 1440 * PointsPerPixel ' Example of what we did ...

A common way to make it more concise would be to avoid creating the extra constants and just manually include the 72 points per inch and the 96 pixels per inch constants for the current monitor as plain numbers.

.Left = 1440 * 72 / 96 ' Scary hidden VBA error!

[Dusts hands off]

There, we’re done—

Uhhh … but this causes an error!!!

Yeah, I mean the triple exclamation points. This is horrible because it’s so subtle. There is nothing logically wrong with the calculation. It seems like we’re avoiding using any extra constants resulting in a more concise macro, but the macro crashes.

Even declaring the stored variable as a Long number type (a very large counting number) doesn’t work!

Dim SomeNumber As Long

Surely this will solve the issue?

SomeNumber = 1440 * 72 / 96 ' Still an error!

Actually, this is the same thing we we’re doing with the Left property above since it is already a Long number type, so it’s no wonder we get the same error.

Whoa …

VBA errors like this are unacceptable. Like really, really bad. It’s like discovering a buried computer virus from ancient Egypt. How do you even realize what’s happening when they wrote their VBA code in hieroglyphics?

So subtle. What’s going on?

Clues ...

We can get a clue when we realize this variation works.

.Left = 1440 / 96 * 72 ' This works?

In the first version, VBA is doing the multiplication first because it is the first operation (remember, multiplication and division have a same precedence in mathematics), but 1440 * 72 = 103680. This number exceeds the maximum Integer number type (of 32767), so it causes an error in the calculation. VBA assumes an Integer type not a Long for explicit numbers even though we’re storing it in a variable with a Long number type. VBA would eventually “cast” the Integer result into a Long to store it in the Left property as the last step, but it never gets there in the former case because of the intermediate Integer “overflow” error.

Whoa!

That’s just unbelievable in modern programming (VBA is showing its age here).

The second version works because 1440 / 96 = 15, so the subsequent multiplication by 72 as 15 * 72 = 1080 is within the range of allowed values for an Integer.

Solutions

We can get around this by forcing VBA to use a Long number type with CLng(…) on at least one of the first two numbers.

.Left = CLng(1440) * 72 / 96 ' This works

This works, but it’s rather clunky.

Wowser. What a weird ancient bug. Am I exclaiming too much? I’m just flabbergasted.

Other alternatives include declaring intermediate Long variables or constants to again force the calculation as a larger Long number type. This is why our initial declaration of Long number type constants didn’t reveal the error, but it still lurked under the ancient ruins.

By the way, uber concise code like this might be tempting, but it’s also harder to read later unless you add comments, … but then you might as well use the extra lines to declare the more readable constants.

Position and size number types

We’re safe here if you want to skip ahead to the final macros, but given the above problem we might be scared enough to double check a few other calculations.

Other places we might need to be careful with conversion errors include VBA rounding our multiplication of an Integer number with a Double number.

.Left = -1920 * PointsPerPixel

The -1920 value is an Integer in VBA, but PointsPerPixel is a Double number type since we declared it as such earlier. VBA does the numeric conversions behind the scenes to carry out the multiplication, but we should be careful and at least test our macro for various cases to see if it acts like we expect.

Breaking it down …

When we use our above constant, we’re multiplying a counting number in pixels (for us humans) by a floating point number. The result is always a floating point number.

No problem so far.

Then we store that result in a Long number type property (Left, Top, Height, or Width). VBA automatically does this conversion for us also, so we’re still safe. The number of points is generally large for a window on a modern monitor, so we shouldn’t expect much round off error.

Where could we hit a small problem?

Rounding numbers with exactly a decimal of x.5 may go the wrong direction compared to what you expect since it rounds to the nearest even number.

Hmmm.

It’s standard practice but not an obvious one since they probably didn’t teach it like that in elementary school. Still, when we’re talking about pixel positions on a monitor, we probably would not even notice a point or pixel one way or the other unless you’re a certain college professor that is a perfectionist …

So we’re basically okay here.

Whew … moving on.

Integer division?

We’re safe here also if you want to skip ahead to the final macros, but we should probably at least consider one other number-related programming issue, so it doesn’t surprise us later.

If you prefer the more concise scale factor for pixels to points, a ghost gotcha with our constants might worry anyone familiar with programming in other languages.

Const PointsPerPixel As Double = 72 / 96

The seeming counting numbers, 72 and 96, here might be scarily evaluated using Integer division (which is different than floating point division). Integer division truncates the answer with no remainder, so we get an Integer (or whatever counting number type we’re using). If so, the Integer result would then be converted to a floating point value.

In the above example, it’s the difference between a final value of 0.0 compared to the expected value of 0.75, and several prominent programming languages use the number types to determine the type of division.

We could be careful and use VBAs floating point notion.

Const PointsPerPixel As Double= 72# / 96# ' Not necessary

But this is just ugly. Yuck.

In other languages, including decimals like 72.0 and 96.0 would ensure the expression is evaluated as a floating point number, but in VBA, a forward slash is automatically assumed to be floating point division. VBA has a separate symbol backslash \ for integer division.

Whew.

Fortunately, VBA doesn’t mess up this calculation.

Inconsistent results

Many times, I’ve actually run the same macro with the same settings and had the window resize differently, so don’t expect perfection from the layout settings. If it does something weird with the layout, you might try just running the macro again. This bothers me as a programmer since it shouldn’t happen, but I’ve experienced it multiple times.

Mixed monitor size issues

The final layout macro doesn’t play nice with different monitors in the same setup since it cannot automatically detect the different monitor resolutions nor pixels sizes.

Ughhh.

That means this macro isn’t as clean as most of the others on this site, but this is mostly outside my control. Trying to autodetect specific system information inside VBA is far outside the scope of this site.

I mentioned the previous multimonitor setup I used for writing. I had three 1920 x 1200 identical monitors, so everything worked nice. Due to various constraints, my current setup uses an older 1920 x 1200 monitor on the left, a more recent 4K monitor at 3180 x 2160 in the middle, and my Surface Pro screen to the right at 2880 x 1920.

My Mac setup is similar with the laptop on the left at a 2560 x 1600 resolution and a larger (physically but not in pixel size or resolution), older 1920 x 1200 monitor on the right.

Fun, right?

It’s not my preferred setup, but I acquired the MacBook and the Surface Pro at different times for different reasons. I definitely recommend multiple monitors to be more productive (or an ultrawide monitor), but the different resolutions are aggravating at times.

On my old same-monitor setup, I would display my novel usually across the left two monitors, and the layout macros would work fine spanning both monitors because they were identical. It doesn’t work well with my newer setup, but spanning two monitors with a single document is probably something I personally do, but it probably wouldn’t be common practice for others.

That’s not to say the macro below won’t work at all, but the scale factor will just be wrong for the different monitor(s), so you would need to tinker with the numbers to get the desired size or position on the second monitor. Definitely a hack solution, and it acts weirder near the edges of the different resolution monitors. Windows 11 also resists positioning windows near the screen edges without maximizing them.

What works well is keeping the Word window within the main (usually central) monitor where the pixel size value is valid. Fortunately, this is the most common case.

Final layout macros

Putting it all together, we get our base Word layout macros. Unfortunately, enough differences exist that we need two versions of the macro.

Both would need to be adjusted for your own preferences and setup. You also need to insert your pixels per inch value for your working monitor in the named constant below. I even wrote the macro and forgot to do this when moving to my Surface Pro setup, so don't forget this important change.

For Windows

In Windows, we can include the Navigation Pane, and the position and size properties use points.

Sub LayoutNovelWindow()
' Reposition the active window on the left side of a wide screen (not maximized)
' Set a zoom setting with a multipage layout
' Place Navigation Pane floating to the right

' Make sure at least one document is open before continuing
If Documents.Count = 0 Then Exit Sub

' Define pixels to points conversion for position and size properties
Const PointsPerInch As Double = 72.0 ' Size of point unit
Const PixelsPerInch As Double = 96.0 ' Pixel density for monitor
' Pixel to points scale factor for current monitor
Const PointsPerPixel As Double = PointsPerInch / PixelsPerInch

' Position and resize the ActiveWindow by converting pixels to points
With Application.ActiveDocument.ActiveWindow
.Top = 0 ' No scale factor for zero
.Left = -1920 * PointsPerPixel
.Width = 3840 * PointsPerPixel
.Height = 1128 * PointsPerPixel
End With

' Adjust zoom and how many pages are displayed
With Application.ActiveDocument.ActiveWindow.View.Zoom
.PageColumns = 2
.PageRows = 1
.Percentage = 180 ' Must set after pages
End With

' Place floating Navigation Pane right of the Word window
With Application.CommandBars("Navigation")
.Position = msoBarFloating
.Visible = True

' Error occurs with all but Width assignment if pane is docked
.Top = 0
.Left = 1930
.Width = 420
.Height = 1128 ' Omit when using a docked pane
End With
End Sub

Honestly, the VBA editor will override the notation for 72.0 and 96.0 to 72# and 96#, but I just can’t … no. Sometimes you gotta ride a lame horse, but it don’t make it right.

For Mac

The Mac version does not recognize the Navigation Pane stuff, so we remove those steps, and the position and size properties use pixels not points (regardless of the documentation), so point conversions are not needed.

Sub LayoutNovelWindowMac()
' Reposition and resize the active window to full screen (not maximized)
' including a multiple page layout with zoom settings

' Make sure at least one document is open before continuing
If Documents.Count = 0 Then Exit Sub

' Position and resize the ActiveWindow in pixels (despite the documentation)
With Application.ActiveDocument.ActiveWindow
.Top = 0
.Left = -1920
.Width = 2880
.Height = 1080
End With

' Adjust zoom and how many pages are displayed
With Application.ActiveDocument.ActiveWindow.View.Zoom
.PageColumns = 2
.PageRows = 1
.Percentage = 180 ' Must set after pages
End With
End Sub

What settings to use?

Do we just make up numbers and tweak them until we get something close to what we want?

Of course not. Position and size the window how you like and then run a quick utility macro to output your approximate settings. Recall the standard MsgBox function allows us to report some information to the user when a macro runs.

MsgBox "Some message in double quotes or with string variables or plain text constants"

Since the function requires a plain text argument, any numbers need a CStr(...) function to convert the value to a text format for the function (alternatively use an ampersand & character to "add" them to the other text).

CStr(MyNumericalValue)

We can then output our settings with something like the following macro. Plus + signs add various text elements together to create our message. This is called string "concatenation," but in the end, it just gives us a convenient way to include useful information in the message.

Sub GetMyActiveWindowLayoutSettings()
' Display settings for active window position and size

' Define pixels to points conversion for position and size properties
Const PointsPerInch As Double = 72# ' Size of point unit
Const PixelsPerInch As Double = 96# ' Pixel density for U2412M monitor
' Pixel to points scale factor for current monitor
Const PointsPerPixel As Double = PointsPerInch / PixelsPerInch

' Output popup message with layout settings of the ActiveWindow
With Application.ActiveDocument.ActiveWindow
MsgBox "ActiveWindow position and size settings in points are:" + vbCr + _
"Top is " + CStr(.Top) + " and Left is " + CStr(.Left) + vbCr + _
"Width is " + CStr(.Width) + " and Height is " + CStr(.Height) + vbCr + _
"Usable Width is " + CStr(.UsableWidth - 1) + _
" and Usable Height is " + CStr(.UsableHeight - 1) + vbCr + vbCr + _
"In pixels the values are:" + vbCr + _
"Top is " + CStr(.Top / PointsPerPixel) + _
" and Left is " + CStr(.Left / PointsPerPixel) + vbCr + _
"Width is " + CStr(.Width / PointsPerPixel) + _
" and Height is " + CStr(.Height / PointsPerPixel) + vbCr + _
"Usable Width is " + CStr((.UsableWidth - 1) / PointsPerPixel) + _
" and Usable Height is " + CStr((.UsableHeight - 1) / PointsPerPixel) + _
+ vbCr + vbCr + "Points per pixel is " + CStr(PointsPerPixel)
End With
End Sub

MsgBox works in both Windows and Mac. The function includes some bells and whistles options to prettify the dialog, but we're just using a plain farm horse version. The message has to be all plain text anyhow. The special constant vbCr is the text return character.

The minus 1 on the UsableHeight or UsableWidth properties is because of how Microsoft offset the values (for some reason, having no usable height or width returns a value of 1 which I think is a conceptual mistake). We're dividing by the PointsPerPixel scale factor because we're converting back from points, as understood by the properties, back to pixels for us. In the main macro above, we multiplied by the constant because were converting from pixels to points to get points as expected by the properties.

Now you can enter the reported tentative values into your other layout macro and tweak them to the pixel if needed. Of course, you still need to insert the pixel size for your particular monitor for the pixel values to be meaningful, but these values will get you close to what you want because you determined the layout for your particular setup.

I prefer to keep all this to one popup dialog, so the message uses line continuation characters at the end of most lines with some indenting to make it easier to read in the VBA editor (VBA does not care). If you want to do things like this for other macros or settings, there is a limit of 25 lines for a single statement meaning no more than 24 line continuations.

Improvements

I usually put this layout macro in the standard Word AutoOpen macro which we introduce in the next article, so I don’t need to run it manually. I create three variations for writing a novel with two to four full book size pages on screen. I also have two other variations for placing my automatically generated outline or novel notes documents.

Other interesting View methods or properties

I haven’t used this much personally, but it’s not difficult to change the expanded or collapsed heading views using:

ActiveWindow.View.CollapseAllHeadings
ActiveWindow.View.ExpandAllHeadings

The corresponding commands for a particle heading level are:

ActiveWindow.View.ShowAllHeadings
ActiveWindow.View.ShowHeading Level:=1 ' Heading level number

In practice, I found using collapsed headings are too slow for a novel after it grows past a few chapters, so I ended up creating a macro to extract the novel headings and notes (which I include as I write and edit) into a separate document. Everything is nice and color coded and easy to read. Then I made a more advanced find macro to jump to the appropriate content between the documents. Both macros should eventually appear on this site at least for members.

The methods above are technically available in Word for Mac VBA, but I had some issues during testing, so proceed with caution.

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.