Yes. In Excel VBA for Windows, you can keep a UserForm above other windows by calling the Windows API function SetWindowPos and marking the form as topmost. The setting applies to the form window—not just to Excel—and is not available in Excel for Mac or Excel for the web.
What “on top” means for a VBA UserForm
Windows maintains a z-order: the order in which windows overlap. A normal window can be covered when another application is brought forward. A topmost window stays above ordinary, non-topmost windows even when the user switches to another application. That is useful for a small control panel, a reference form, or a modeless data-entry window that should remain visible beside a spreadsheet.
Topmost does not mean immovable, uncloseable, or guaranteed to cover every possible window. Another topmost window can appear above it, and Windows may display system interfaces or security prompts in front. It also does not make the UserForm a child of a worksheet or keep it inside Excel’s window. The distinction matters: a form set topmost can cover unrelated applications, which may be surprising to users.
How the Windows API approach works
The API call SetWindowPos can change a window’s position in the z-order. Passing the special value -1 as its “insert after” handle corresponds to HWND_TOPMOST; passing -2 corresponds to HWND_NOTOPMOST and removes the topmost status. Flags tell Windows not to move or resize the form while changing that status.
VBA does not provide a built-in UserForm property such as AlwaysOnTop. The code therefore needs two pieces: a window handle (the operating system’s identifier for the form window) and the API declaration. The example below looks up the form by its common MSForms window class and its caption. Put it in the UserForm’s code module, replacing the event name or adding the call to an existing event as needed.
Example code for a UserForm
This example makes the form topmost when it activates. It uses pointer-sized declarations in VBA7, which covers current Microsoft 365 Excel for Windows and both 32-bit and 64-bit Office. Save a copy of the workbook before running macros: VBA actions cannot be undone with Ctrl+Z.
#If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As LongPtr, ByVal hWndInsertAfter As LongPtr, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal uFlags As Long) As Long
#Else
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal uFlags As Long) As Long
#End If
Private Const SWP_NOSIZE As Long = &H1
Private Const SWP_NOMOVE As Long = &H2
Private Const SWP_NOACTIVATE As Long = &H10
Private Sub UserForm_Activate()
SetFormTopMost True
End Sub
Private Sub SetFormTopMost(ByVal makeTopMost As Boolean)
#If VBA7 Then
Dim formHwnd As LongPtr
Dim insertAfter As LongPtr
#Else
Dim formHwnd As Long
Dim insertAfter As Long
#End If
' Find this form by its common MSForms class and caption.
formHwnd = FindWindow("ThunderDFrame", Me.Caption)
If formHwnd = 0 Then Exit Sub
If makeTopMost Then
insertAfter = -1 ' HWND_TOPMOST
Else
insertAfter = -2 ' HWND_NOTOPMOST
End If
' Change z-order without moving, resizing, or activating the form.
SetWindowPos formHwnd, insertAfter, 0, 0, 0, 0, _
SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE
End Sub
The constants are Windows API flags: SWP_NOMOVE and SWP_NOSIZE preserve the current geometry, while SWP_NOACTIVATE avoids asking Windows to activate the window as part of the call. The form’s Activate event already occurs when it becomes active. If your form has other code in that event, keep it and add SetFormTopMost True rather than replacing the existing procedure.
Show the form modelessly when appropriate
A modeless form lets the user continue working in Excel while it stays open. From a standard module, the usual call is UserForm1.Show vbModeless, using your actual form name. A modal form, shown with UserForm1.Show or vbModal, blocks interaction with the rest of Excel until it is hidden or unloaded. Topmost changes the window’s z-order; it does not change modal versus modeless behavior.
For a floating utility window, modeless display is generally the more useful pairing. However, modeless forms can remain open while the user selects cells, changes sheets, or switches applications, so make sure the form’s controls and event code handle those actions sensibly. If the form is intended only to collect a required answer before the macro continues, modal display may be the better choice even if the form is also topmost.
How to remove the topmost setting
Topmost status is a window setting, not a permanent workbook setting. When the window is destroyed, its z-order state goes away. If your code hides the form instead of unloading it, though, the window may retain that state while hidden and appear topmost again when shown. You can remove the status before hiding the form by calling SetFormTopMost False from the form’s Hide button event, or before unloading if you want an explicit reset.
For example, a button that should return the form to ordinary z-order before hiding it can run SetFormTopMost False and then Me.Hide. If the form should remain topmost whenever it is shown, omit that reset and let the Activate event apply the setting again. Consider the intended behavior carefully: there is a difference between “topmost while this tool is open” and “topmost every time the user brings this form forward.”
Choosing a reliable way to find the form
The sample uses FindWindow with the class name ThunderDFrame, a commonly used class for classic Microsoft Forms UserForms. It then matches the caption. This is a practical technique, but the class name is an implementation detail rather than a VBA guarantee. The lookup can fail if the window class differs in a particular environment, or identify the wrong window if two open forms have the same caption and class.
Give forms distinct captions if you may have multiple instances open, and check that the lookup returned a nonzero handle before calling SetWindowPos. If the form is not found, do not pass a zero handle onward and assume the operation succeeded. For a more specialized solution, developers sometimes obtain the foreground window handle during the form’s activation and use that handle instead. That approach also needs careful validation: the foreground window is whichever window Windows considers active at that moment, so it should not be assumed to identify the form in every timing or focus scenario.
Common problems and troubleshooting
- Compile error on a 64-bit installation: API declarations must use
PtrSafein VBA7, and window handles must useLongPtr. The conditional declarations above support VBA7 and older VBA, rather than using a 32-bitLongfor handles on 64-bit Office. - The form is not found: Confirm that the caption passed to
FindWindowmatchesMe.Caption, and that the class name is correct for the environment. Duplicate captions can cause ambiguity. - The form jumps or activates unexpectedly: Keep the no-move, no-size, and no-activate flags. Avoid calling the API repeatedly from fast-running code; call it when the form is shown or activated instead.
- It stays above other applications: That is expected for a topmost window. Reset it with
HWND_NOTOPMOSTbefore hiding or when topmost behavior is no longer wanted. - It still goes behind something: Topmost means above ordinary windows, not every possible system or topmost window. It is not a guarantee against every window-management action.
Compatibility and safer design choices
This method calls user32, a Windows system library, so it applies to desktop Excel for Windows. Excel for Mac does not provide the Windows API used in the example, and Excel for the web does not run VBA macros. A workbook intended for users on multiple platforms should not rely on this code as its only way to present essential information.
Also consider whether the form truly needs to cover other programs. If the task is Excel-specific, alternatives include positioning the modeless form beside the worksheet, reducing its size, or keeping relevant instructions in worksheet cells. A topmost form can obscure a user’s work in another application and may feel intrusive. If the requirement is only to keep a form above Excel windows, a system-wide topmost API call may be broader than necessary; Windows APIs do not automatically scope this flag to one workbook.
Frequently Asked Questions
Can I keep a VBA UserForm on top without an API?
No built-in VBA UserForm property provides general always-on-top behavior. The Windows API method is the common desktop Windows approach. If API use is unsuitable, redesigning the workflow or keeping information in the worksheet avoids that dependency.
Does Me.Show vbModeless make the form stay on top?
No. vbModeless lets the user interact with Excel while the form remains open, but it does not set the form as topmost. Modeless behavior and topmost z-order are separate settings.
Will the code work in 64-bit Excel?
It is written with VBA7 conditional declarations and LongPtr handles for 64-bit compatibility. Use the code in desktop Excel for Windows, and preserve the declarations exactly; changing a handle to a plain Long can cause problems in 64-bit Office.
Can I make the UserForm stay on top only of Excel?
The HWND_TOPMOST setting is a Windows z-order status, not an Excel-only setting. It can keep the form above ordinary windows from other applications too. There is no simple UserForm property that limits topmost status to one workbook.
Why does my form appear behind another window anyway?
Check that the API found the correct form handle and that the Activate event runs. A duplicate caption, a different window class, or a separate topmost window can explain the result. The topmost flag does not outrank every other topmost or system window.
Related
- Remove a Dropdown List in Excel Without Losing Data
- Excel Redo Shortcut: How to Restore an Undone Action
- Protect Excel Sheets in Teams: What It Does and How
Try it: the Column Letter to Number: aA is 27, XFD is 16,384. Converts both ways.
More in VBA & macros
- Excel VBA Evaluate: How It Works and When to Use ItIn Excel VBA, Application.Evaluate interprets a text expression using Excel’s formula language and returns the result as a…
- Excel VBA: How to Save a Backup Copy of a WorkbookTo save a backup copy of the workbook that contains your VBA code, use ThisWorkbook.SaveCopyAs fullPath. For example,…
- VBA Copy Range and Paste as Values in ExcelTo copy an Excel range and paste only its values with VBA, copy the source range and use…
- Excel VBA: Check Whether a Dynamic Array Is AllocatedNo—VBA arrays are not objects, so If myArray Is Nothing is not a valid way to test one.…
- Access VBA Error Handling: Trapping and Fixing ErrorsAccess VBA error handling lets a procedure respond when a runtime error occurs instead of stopping unexpectedly. Use…
- Excel VBA: Get the Current Workbook File Path EasilyIn Excel VBA, use ThisWorkbook.Path to get the folder path of the workbook that contains the code, or…
Sources: Function behaviour and menu paths: Microsoft Support documentation for Excel. Method & sources
Spotted an error in this guide? Let us know.