Python: template_ID()-like UI for PropertyGroup
It is possible to create a group of inputs that behaves very similar to the normal chooser. This is the code to draw the widgets:

def draw_buttons(self, context, layout):
    group = layout.row(align=True)
    choose_props = group.operator('example.choose_item', text="", icon='PRESET')
    if self.item_set:
        group.prop(self.get_item(), "name", text="", expand=True)
        clear_props = group.operator('example.clear_item', icon='X', text="")
        clear_props.node_tree = self.id_data.name
        clear_props.node = self.name
    else:
        new_props = group.operator('example.new_item', icon='ADD', text='New')
        new_props.node_tree = self.id_data.name
        new_props.node = self.name
    choose_props.node_tree = self.id_data.name
    choose_props.name = self.name


The choose operator itself uses context.window_manager.invoke_search_popup() to open a search box of available items. Here is example code for the operators:

items = [('one', 'Any', "", 'PRESET', 1), ('two', 'PropertyGroup', "", 'PRESET', 2), ('three', 'type', "", 'PRESET', 3)]

class ChooseItemOperator(bpy.types.Operator):
    bl_idname = "example.choose_item"
    bl_label = "Choose item"
    bl_options = {'INTERNAL'}
    bl_property = "enum"

    def get_enum_options(self, context):
        global items
        return items

    enum: EnumProperty(items=get_enum_options, name="Items")
    node_tree: StringProperty()
    node: StringProperty()

    def execute(self, context):
        tree = bpy.data.node_groups[self.node_tree]
        node = tree.nodes[self.node]
        node.item_set = true
        node.set_item(self.enum)
        return {"FINISHED"}

    def invoke(self, context, event):
        context.window_manager.invoke_search_popup(self)
        return {"FINISHED"}

class NewItemOperator(bpy.types.Operator):
    bl_idname = "example.new_item"
    bl_label = "New Item"
    bl_options = {'INTERNAL'}

    node_tree: StringProperty()
    node: StringProperty()

    def execute(self, context):
        global items
        tree = bpy.data.node_groups[self.node_tree]
        node = tree.nodes[self.node]
        node.item_set = True
        newitem = ('four', 'type', "", 'PRESET', 4)
        items.append(newitem)
        node.set_item(newitem)
        return {'FINISHED'}

class ClearItemOperator(bpy.types.Operator):
    bl_idname = "example.clear_item"
    bl_label = "Clear Item"
    bl_options = {'INTERNAL'}

    node_tree: StringProperty()
    node: StringProperty()

    def execute(self, context):
        tree = bpy.data.node_groups[self.node_tree]
        node = tree.nodes[self.node]
        node.item_set = False
        return {'FINISHED'}


Of course this is just example code and adding new items should be smarter than just adding items to a global list, but this is the general idea.