This site is currently in read-only mode during migration to a new platform.
You cannot post questions, answers or comments, as they would be lost during the migration otherwise.
+2 votes

How to make a folding menu like this:
(they looks like a drawer, usually its closes.
When one is opened, expand the window it contains and squeeze down the other drawers)

enter image description here

in Engine by (59 points)

1 Answer

+3 votes
Best answer

Here is an example of a custom node that works like an accordion.

enter image description here

enter image description here

The Control moves each child to the end of the previous one (only in the y direction)
enter image description here

extends Control

export var spacing = 10

func _draw():

    var last_end_achor = Vector2.ZERO
    for child in get_children():
        child.rect_position = last_end_achor
        last_end_achor.y = child.rect_position.y + child.rect_size.y 
        last_end_achor.y += spacing

    rect_min_size.y = last_end_achor.y #to work with ScrollContainer

And clicking on the button "show" toggles the parent "Panel" size to the open or the closed value.
enter image description here

extends Panel

var is_expanded = false

func _ready():

func expand():
    is_expanded = !is_expanded

var last_rect_size = Vector2.ZERO
func _process(delta):

    #snap to end
    if abs(rect_size.y-rect_min_size.y) < 1:
        rect_size.y = rect_min_size.y

    #resize to target size
    if is_expanded:
        rect_size.y = lerp(rect_size.y, 70, 0.1)
        rect_size.y = lerp(rect_size.y, rect_min_size.y, 0.1)

    #update layout
    if last_rect_size != rect_size:
        last_rect_size = rect_size
by (1,003 points)
selected by


I followed your instruction to make this menu. But the items in panel didn't close. Can you help?

What I have done to make this work is to make the show button a child of the root and then set "Clip Content" in the panel rect properties to true.

Now the content of the panel will shrink with the panel.

If I find the time I will post an github project with an working reusable example.

For me that solution doesn't work well with spinbox. It makes an overflow due to callback update. I have done a simpler script on a VBoxContainer and a button "show" as his child and it seems to work.

extends VBoxContainer

export var is_expanded = true

func _ready():

func expand():
    is_expanded = !is_expanded
    for child in get_children():
        child.visible = true if is_expanded else child == $show
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.