Best way to store options for panels
Blender 2.8 has sub panels.

As of blender 2.8 can if bl_parent_id is set in a panel it will be appended to the parent panel. Use the usual 'DEFAULT_CLOSED' in the bl_options set to start with panel closed.

This avoids needing to set up some boolean property to open close UI altogether.

Here is a sample file I've been testing for ordering panels.  First panel is defined as a child of the object transform panel. Second panel is a child of first. Can unregister and re-register with different parent ids to sort sub-panels, which is what I was testing


The two demo sub panels appended to object transform

import bpy
from bl_ui.properties_object import ObjectButtonsPanel, OBJECT_PT_transform

class LayoutDemoPanel(bpy.types.Panel, ObjectButtonsPanel):
    bl_label = "Layout Demo"
    bl_idname = "SCENE_PT_layout"
    bl_parent_id = 'OBJECT_PT_transform'
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'

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

        scene = context.scene

        # Create a simple row.
        layout.label(text=" Simple Row:")

        row = layout.row()
        row.prop(scene, "frame_start")

class LayoutDemoPanel2(bpy.types.Panel, ObjectButtonsPanel):
    bl_label = "Layout Demo 2"
    bl_idname = "SCENE_PT_layout2"
    bl_parent_id = 'SCENE_PT_layout'
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'

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

        scene = context.scene

        # Create a simple row.
        layout.label(text=" Simple Row:")

        row = layout.row()
        row.prop(scene, "frame_start")


def register():
    bpy.utils.register_class(LayoutDemoPanel)
    bpy.utils.register_class(LayoutDemoPanel2)

def unregister():
    bpy.utils.unregister_class(LayoutDemoPanel2)
    bpy.utils.unregister_class(LayoutDemoPanel1)


if __name__ == "__main__":
    register()


If you have some logical setting that when set needs more UI How to dynamically show/hide panel elements using python?