Skip to content

Tabs

Tabs widgets are Layout Fields that allow users to switch between different content areas within the same context. They are highly effective for breaking down large forms into logical, manageable pieces.

tabs.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.layouts.tabs([
{
label: 'Personal',
uid: 'tab_personal',
children: [
gui.inputs.textInput('personal_email', {
label: 'Personal Email',
}),
],
},
{
label: 'Work',
uid: 'tab_work',
children: [
gui.inputs.textInput('work_email', {
label: 'Work Email',
}),
],
},
{
label: 'Other',
uid: 'tab_other',
children: [
gui.inputs.textarea('notes', {
label: 'Additional Notes',
}),
],
},
], {
defaultOpen: 'tab_personal',
uid: 'tabs_basic',
}),
];
tabs.json
{
"form": [
{
"uid": "tabs_basic",
"kind": "layout",
"type": "tabs",
"props": {
"tabs": [
{ "uid": "tab_personal", "label": "Personal" },
{ "uid": "tab_work", "label": "Work" },
{ "uid": "tab_other", "label": "Other" }
],
"defaultOpen": "tab_personal"
},
"children": [
{
"uid": "tab_personal",
"kind": "input",
"type": "textinput",
"path": "personal_email",
"label": "Personal Email"
},
{
"uid": "tab_work",
"kind": "input",
"type": "textinput",
"path": "work_email",
"label": "Work Email"
},
{
"uid": "tab_other",
"kind": "input",
"type": "textarea",
"path": "notes",
"label": "Additional Notes"
}
]
}
]
}

Use these props to customize your Tabs widget.

proptypedescription
tabsarrayRequired. Array of tab definitions: { label: string, uid: string }. Each uid must match the uid of one of the children.
defaultOpenstringThe uid of the tab that should be active on initial render. Defaults to the first tab
renderModestring'all' keeps every tab panel mounted in the DOM and toggles visibility; 'activeOnly' mounts the active tab’s children only while it is open. Defaults to 'all'

Use defaultOpen to select which tab is active on first render. Set it to the uid of any tab — here, the second tab is selected on load.

tabs.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.layouts.tabs(
[
{
label: 'Personal',
uid: 'tab_personal',
children: [gui.inputs.textInput('personal_email', { label: 'Personal Email' })],
},
{
label: 'Work',
uid: 'tab_work',
children: [gui.inputs.textInput('work_email', { label: 'Work Email' })],
},
{
label: 'Other',
uid: 'tab_other',
children: [gui.inputs.textarea('notes', { label: 'Additional Notes' })],
},
],
{
defaultOpen: 'tab_work',
uid: 'tabs_default_open',
},
),
];
tabs.json
{
"form": [
{
"uid": "tabs_default_open",
"kind": "layout",
"type": "tabs",
"props": {
"tabs": [
{ "uid": "tab_personal", "label": "Personal" },
{ "uid": "tab_work", "label": "Work" },
{ "uid": "tab_other", "label": "Other" }
],
"defaultOpen": "tab_work"
},
"children": [
{
"uid": "tab_personal",
"kind": "input",
"type": "textinput",
"path": "personal_email",
"label": "Personal Email"
},
{
"uid": "tab_work",
"kind": "input",
"type": "textinput",
"path": "work_email",
"label": "Work Email"
},
{
"uid": "tab_other",
"kind": "input",
"type": "textarea",
"path": "notes",
"label": "Additional Notes"
}
]
}
]
}

Use renderMode to control when tab children are mounted. The default 'all' keeps every panel in the DOM and hides inactive ones, which preserves child state and form values as the user switches tabs. Use 'activeOnly' to mount a tab’s children only while it is active — useful when panels contain expensive widgets, side effects on mount, or media you don’t want loaded up front. Inspect the rendered DOM as you switch tabs to see the difference.

tabs.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.layouts.tabs(
[
{
label: 'Personal',
uid: 'tab_personal',
children: [gui.inputs.textInput('personal_email', { label: 'Personal Email' })],
},
{
label: 'Work',
uid: 'tab_work',
children: [gui.inputs.textInput('work_email', { label: 'Work Email' })],
},
{
label: 'Other',
uid: 'tab_other',
children: [gui.inputs.textarea('notes', { label: 'Additional Notes' })],
},
],
{
defaultOpen: 'tab_personal',
renderMode: 'activeOnly',
uid: 'tabs_render_mode',
},
),
];
tabs.json
{
"form": [
{
"uid": "tabs_render_mode",
"kind": "layout",
"type": "tabs",
"props": {
"tabs": [
{ "uid": "tab_personal", "label": "Personal" },
{ "uid": "tab_work", "label": "Work" },
{ "uid": "tab_other", "label": "Other" }
],
"defaultOpen": "tab_personal",
"renderMode": "activeOnly"
},
"children": [
{
"uid": "tab_personal",
"kind": "input",
"type": "textinput",
"path": "personal_email",
"label": "Personal Email"
},
{
"uid": "tab_work",
"kind": "input",
"type": "textinput",
"path": "work_email",
"label": "Work Email"
},
{
"uid": "tab_other",
"kind": "input",
"type": "textarea",
"path": "notes",
"label": "Additional Notes"
}
]
}
]
}

Tabs can be styled as explained in the Styling Guide.

Following you will find a list with the CSS Variables used to style the tabs.

CSS VariableDescription
--gui-bg-defaultBackground color for tab buttons and panels
--gui-border-defaultBorder color for tab buttons and panels
--gui-text-defaultText color for labels
--gui-space-3Padding inside tab buttons and panels
--gui-radius-mdBorder radius for tab buttons and panels

This is the anatomy of the Tabs Widget in case you want to use your CSS styles.

tabs-anatomy.html
<div class="gui-tabs">
<nav class="gui-widget gui-widget--horizontal" id="tabs_uid">
<ul role="tablist">
<li role="presentation">
<button type="button" role="tab" aria-selected="true" class="active" id="tab_tabs_uid_0">
Personal
</button>
</li>
<li role="presentation">
<button type="button" role="tab" aria-selected="false" id="tab_tabs_uid_1">
Work
</button>
</li>
<li role="presentation">
<button type="button" role="tab" aria-selected="false" id="tab_tabs_uid_2">
Other
</button>
</li>
</ul>
</nav>
<section role="tabpanel" id="tabpanel_tabs_uid_0" aria-labelledby="tab_tabs_uid_0">
<div class="gui-widget">
<!-- Child widgets for Personal tab -->
</div>
</section>
<section role="tabpanel" id="tabpanel_tabs_uid_1" aria-labelledby="tab_tabs_uid_1" hidden>
<!-- Content for Work tab (hidden) -->
</section>
<section role="tabpanel" id="tabpanel_tabs_uid_2" aria-labelledby="tab_tabs_uid_2" hidden>
<!-- Content for Other tab (hidden) -->
</section>
</div>