Making User Interface with Python (Blender 2.8)?

I tried scouring through the documentation and looked at the preset templates in the scripting workspace and I still can’t get my head around this stuff.

The main issue here is I don’t know what my options are in terms of UI creation because sometimes the script doesn’t seem to be doing anything. When it does you don’t know where it pops up. I can gather what some of them do but that was only after I searched through the software to find the output of the script.

My main interest is in the WorkSpaceTool type so I can get a button right on the left panel but the documentation doesn’t seem to help that much. The documentation really lacks visuals even though I assume the best way to know how UI works is by showing the visual output.

All this talk about ‘panels’, ‘menus’, ‘lists’ aren’t terribly helpful without visuals.

I guess my question is:

  1. What options do I have for UI scripting?
  2. how do I use WorkSpaceTool Properly?

WorkSpaceTool is a class for the active workspace tool. If you’re looking to add a simple button to an existing panel, you need to look at the panel class.

The panel on the left side of the viewport is called VIEW3D_PT_tools_active and can be accessed in:


Adding a button or two to this panel boils down to:

  1. Define a menu class that inherits from bpy.types.Menu
  2. Define a draw function inside the class that uses functions from UILayout
  3. Register the new menu class
  4. Append the menu class to an existing panel (eg. bpy.types.SOMEPANEL_PT_panel.append(bpy.types.OBJECT_MT_hello.draw))

If you want to add a collapsible panel, define a class that inherits from bpy.types.Panel instead

A simple example that adds a menu with “Add Cube” operator on top of active tools:

import bpy

class OBJECT_MT_hello(bpy.types.Menu):
    bl_label = "Hello World Panel"

    def draw(self, context):
        layout = self.layout
        row = layout.row()

def register():
#    bpy.types.VIEW3D_PT_tools_active.append(OBJECT_MT_hello.draw)  # << add menu below
    bpy.types.VIEW3D_PT_tools_active.prepend(OBJECT_MT_hello.draw)  # << add menu above

def unregister():
    if hasattr(bpy.types, "OBJECT_MT_hello"):

if __name__ == "__main__":