Tabs
Behavior of Tabs prior to gooey 2025.4
Behavior of tabs was improved in gooey 2025.4; however, this introduced some breaking changes. Throughout this article, I will highlight certain differences, in case you are working with an older version. However, it is strongly recommended to update gooey to the latest version.
When we saw the basic structure of panels, we saw the panel body, and we said it hosted the widgets added to the panel. In reality, the panel will host widgets either in a common widgets body area, or in a specific tab. Additionally, the panel contains a tab group control which allows you to switch between tabs. The schematics are as follows:

If we stripped down the panel, we could see the following simplified structure:

The panel tabs
All panels in gooey have at least one tab (tab index 0, by default) and can have multiple tabs. Whenever you add widgets with the add() method we've seen before, you are really adding to the current tab. If you've just created the panel, the current tab will be the tab with index 0. The add() method has an optional argument to specify to which tab you want to add the widget.
As expected, gooey will only render the current tab. To change between tabs, you can use the built-in tab group control, build one yourself or programatically change tabs.
The common widgets area
Additionally, there is a "special" tab in which common widgets are rendered. The objective of this tab is to render things that we need no matter which tab we are displaying. In particular, things like the panel title, the close button and the actual tab group control, are actually added and rendered in this area - thus being always available.
You can add other widgets to the common widgets area by using tab index -1.
The tab group control
Panels in gooey have a ready-made group of buttons that are automatically managed when adding / removing tabs. By default, the tab group control will only show if there's more than one tab created; however, you can control its visibility by using the setTabControlVisible() panel method.
You can also use various other methods to customize how tab buttons appear, whether the tab group control is horizontal or vertical, etc.
Example
Let's keep building our space colony UI example from the Intro to panels tutorial. We want it to have three tabs (one for unit info, another one for an upgrade shop, and a third one for shields. Let's use the addTab method from the UIPanel constructor to add them:
In the above code we are adding two tabs (since all panels have one "default" tab, tab 0, built in. This yields the following image:
We can see that the tab control has automatically appeared. However, there are some problems:
1) We have not specified any sprite for the tab buttons; this makes them unusable (remember that gooey works exclusively with sprites, hence if there's no sprite the button will not work, since the height of the buttons will be set to 0). 2) The tab control appears at the top of the panel.
To fix this, let's now specify the sprites we want to use (again, courtesy of Wenrexa), and specify the offset of the tab control group relative to the anchor point:
Offset of tab group control
Prior to gooey 2025.4, tab control would always be rendered at the drag bar height. Starting from 2025.4, you can specific a custom offset, however you need to do this manually. Also, bear in mind that x-offset for horizontal tab groups and y-offset for vertical tab groups will be ignored.
After doing this, the panel is looking much better:
We want to also set an appropriate text for each tab. We are going to use some Scribble formatting to include an icon and a name per each tab:
Now, let's add some widgets to each tab so we can see how gooey manages them. We can supply a second argument to the add() method to add a widget to a specific tab:
Finally, let's add a widget to the common widgets zone (we can specify tab index -1 for this):
Let's test the result! Click on each of the tab buttons in the tab control to see the corresponding widgets appear:
We can see that the Accept button appears no matter which tab we're on, and the button that appears corresponds to the tab we selected (since those were added to a specific tab).
Customizing the appearance of tabs
There's more customization we can have when rendering our tabs:
Orientation
We can control whether tabs are rendered horizontally or vertically, by using setVerticalTabs(). By default, tabs are horizontal.
Anchor point
We can control where tabs are rendered, by setting the anchor point for the tab control, using the regular UI_RELATIVE_TO enum and the setTabControlAlignment() method. This means we can display our horizontal tabs at the bottom, for example, by setting them horizontal and choosing BOTTOM_CENTER.
Tab control anchor point changes in gooey 2025.4
Prior to gooey 2025.4, anchor points for tab controls set to SPECIFIC or SPRITE were not correctly honored (see Size behavior below). However, this behavior changed in 2025.4. Anchor points can now be set and will be correctly honored for those types of size behaviors. Note that tab controls set to MAX (the default) will only honor the "vertical component" of the anchor point (if they are horizontal), or "horizontal component" of the anchor point (if they are vertical).
Size behavior
By default, tab buttons are configured to occupy the complete width (or height, if set to vertical) of the panel. So if we have three buttons like in the interactive example above, we can see that each of the buttons will measure one third of the panel width.
However, we can modify this behavior with the setTabSizeBehavior method. This method accepts an enum named UI_TAB_SIZE_BEHAVIOR, and its possible values are:
| Value | Description |
|---|---|
MAX |
Sets each tab button size to 1/nth of the panel width (or height). Its size will dynamically be adjusted as you resize the panel. This is the default behavior. |
SPECIFIC |
Sets all buttons to a specific width (or height), in pixels. The size will not dynamically change when you resize the panel. You can set this size by using setTabSpecificSize. |
SPRITE |
Sets each tab to the width (or height) of its individual sprite. This allows to have different sizes per tab. The size will not dynamically change when you resize the panel. |
Tab margin and spacing
By default, all tab buttons are rendered one next to the other, and the first tab button appears flush with the edge of the tab control. However, you can define margin and spacing between tabs by using setTabMargin and setTabSpacing methods. This will enable you to define tab controls that have spaces between buttons, and that have some margin from the panel edge.
A customized version of the example
For exemplification, let's take a look at the same example as before, but with customization. We add some lines of code below:
While we were at it, I changed the buttons on each tab so that you can play around with some of the settings. The first button in tab 0 will switch between vertical and horizontal tabs (by calling setVerticalTabs); the second one will cycle through the different anchor points (by setting setTabControlAlignment); and the third one will change between MAX and SPECIFIC (SPRITE is not included in the example, but works very similar to SPECIFIC).
Tab actuators
You have at your disposal the following methods. that allow you to programatically interact with tabs. I think they are self-explanatory, but you can always review the API reference:
- For adding tabs, you have already seen that we have
addTab(). We can specify the number of tabs to add. - For changing tabs, we have
nextTab()andpreviousTab(), as well asgotoTab(), the last of which expects an index. - You can delete a tab by using
removeTab(), by specifying the index.
Wrapping up
Tabs bring great flexibility for creating more complex panels for your UI. With several customization options, you can bring your UI to life.