How to Make a Dynamic Dropdown in Blender Python

A frequently asked question I see on various Blender Python boards is how to make a dynamic dropdown. In this post, I will show how to make dynamic dropdown. If you need a refresher on Blender Python API properties, check out our previous post.

Creating a Dynamic Dropdown

We will use the Enum Property with a callback to create a dynamic dropdown.

Register the Enum Property

The basic approach is not complicated. First, we create and register our enum property.

bpy.types.Object.my_enum = bpy.props.EnumProperty(name="myEnum",description="a dynamic list",items=getList)

The Callback Function

Notice that the last parameter, items, is set to getList. getList is a callback function. The callback function is defined as follows:

def getList(scene, context):
    items = []
    if context.object.type == "MESH":
        items += [("1","Mesh Item 1","This is a mesh list."),
                  ("2","Mesh Item 2","This is a mesh list.")]
    else:
        items.append(("2","NotMeshList","This is a non-mesh list."))
        
    return items

A callback function takes two parameters, the scene and context. This function starts by creating an empty list of items. Next, we check whether the selected object is a mesh or not. We then append items based on the selection. The enum property items must be a tuple with at least three elements: identifier, name, and description (all strings). You can optionally include icon and number.

However, be cautious of the code that you put in the callback. In the Blender Gotcha notes, Blender recommends against including complex operations (like calling an Operator) in a callback. The callback is intended to be fast and may create an issue with undo/redo or trigger an infinite loop.

The properties page also gives a warning about using callbacks, noting that the callbacks may be used in a threaded context and should only operate on the data owned by the callbacks datablock. EnumProperties have an additional warning about callbacks stating “There is a known bug with using a callback, Python must keep a reference to the strings returned by the callback or Blender will misbehave or even crash.” If your callback is crashing, consider defining your item list as a global variable to ensure the list is not deleted.

Creating a Panel

Finally, we need a UI panel to test this dynamic list. We create a simple panel in the object properties.

class DynamicPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Dynamic Panel"
    bl_idname = "OBJECT_PT_dynamic"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        layout.prop(context.object,"my_enum",text="abcde")

We register the class.

bpy.utils.register_class(DynamicPanel)

The Full Code

Below is the full code:

import bpy

def getList(scene, context):
    items = []
    if context.object.type == "MESH":
        items += [("1","Mesh Item 1","This is a mesh list."),("2","Mesh Item 2","This is a mesh list.")]
    else:
        items.append(("2","NotMeshList","This is a non-mesh list."))
        
    return items

class DynamicPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Dynamic Panel"
    bl_idname = "OBJECT_PT_dynamic"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        layout.prop(context.object,"my_enum",text="abcde")
    

def register():
    bpy.types.Object.my_enum = bpy.props.EnumProperty(name="myEnum",description="a dynamic list",items=getList)
    bpy.utils.register_class(DynamicPanel)


def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
    register()

Easy Enough?

In conclusion, this approach is incredibly easy. To see the result, run the script. Click into the object properties panel on the right, and you should see a new panel called “Dynamic Panel” with the abcde dropdown. You can see the changing list by clicking between the default cube and default light.

Property panel showing the dynamic dropdown.

You can add complexity by using a collection to simulate an enum property instead. This is useful with a property group if you want to add additional functionality that doesn’t exist in an enum property. Feel free to leave in the comments if this help you. Feel free to leave comments on other Blender Python problems that you have been unable to solve.