How do a create a foldout UI panel? I have an add-on with rather a lot of UI options and am trying to find a way to clean it up so that not all the options need to be shown at once. I've noticed that some of the default tools have foldout sections, but I can't figure out what UI component I need to use to get the same behaviour.

Here is an example of what I'm talking about, showing the Color Picker panel open, but Color Palette and Options panels folded up. Is there a simple UI component I can use to emulate the behaviour and visual style of this in my add-on?
These UI elements are called panels. When using bl_options = {"DEFAULT_CLOSED"} they will start in a closed state.

The following example add-on creates three panels in the sidebar of the 3D View in a closed state, which looks like this:



bl_info = {
    "name": "Multiple panel example",
    "author": "Robert Guetzkow",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D &gt; Sidebar &gt; Example tab",
    "description": "Example with multiple panels",
    "warning": "",
    "wiki_url": "",
    "category": "3D View"}

import bpy


class EXAMPLE_PT_panel_1(bpy.types.Panel):
    bl_label = "Panel 1"
    bl_category = "Example tab"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_options = {"DEFAULT_CLOSED"}

    def draw(self, context):
        layout = self.layout
        layout.label(text="This is panel 1.")


class EXAMPLE_PT_panel_2(bpy.types.Panel):
    bl_label = "Panel 2"
    bl_category = "Example tab"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_options = {"DEFAULT_CLOSED"}

    def draw(self, context):
        layout = self.layout
        layout.label(text="This is panel 2.")


class EXAMPLE_PT_panel_3(bpy.types.Panel):
    bl_label = "Panel 3"
    bl_category = "Example tab"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_options = {"DEFAULT_CLOSED"}

    def draw(self, context):
        layout = self.layout
        layout.label(text="This is panel 3.")


classes = (EXAMPLE_PT_panel_1, EXAMPLE_PT_panel_2, EXAMPLE_PT_panel_3)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)


if __name__ == "__main__":
    register()


Notice that as of Blender 2.8x, we can have sub panels to save even more space:



class EXAMPLE_panel:
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Example Tab"
    bl_options = {"DEFAULT_CLOSED"}


class EXAMPLE_PT_panel_1(EXAMPLE_panel, bpy.types.Panel):
    bl_idname = "EXAMPLE_PT_panel_1"
    bl_label = "Panel 1"

    def draw(self, context):
        layout = self.layout
        layout.label(text="This is the main panel.")

class EXAMPLE_PT_panel_2(EXAMPLE_panel, bpy.types.Panel):
    bl_parent_id = "EXAMPLE_PT_panel_1"
    bl_label = "Panel 2"

    def draw(self, context):
        layout = self.layout
        layout.label(text="First Sub Panel of Panel 1.")

class EXAMPLE_PT_panel_3(EXAMPLE_panel, bpy.types.Panel):
    bl_parent_id = "EXAMPLE_PT_panel_1"
    bl_label = "Panel 3"

    def draw(self, context):
        layout = self.layout
        layout.label(text="Second Sub Panel of Panel 1.")