#8474·egui

Add `WidgetType::Tab`

Author: micfong-zCreated Aug 31, 2026Updated Sep 11, 2026

Is your feature request related to a problem? Please describe. There is no suitable WidgetType for tabs while I was implementing AccessKit support for egui_dock. AccessKit provides accesskit::Role::Tab and other tab-related widgets that will be described by assistive technologies accurately.

Describe the solution you'd like Add a WidgetType::Tab variant mapping to accesskit::Role::Tab, with WidgetInfo::selected triggering set_selected instead of set_toggled for it. Possibly also some way to mark a container Ui as Role::TabList or Role::TabPanel.

Describe alternatives you've considered

Currently I had to override the role after widget_info using accesskit_node_builder:

rust

response.widget_info(|| WidgetInfo::selected(WidgetType::Button, enabled, selected, title));
ui.ctx().accesskit_node_builder(response.id, |node| {
    node.set_role(accesskit::Role::Tab);
    node.set_selected(selected);
    node.clear_toggled();
});

Also tried using other existing WidgetTypes like selectable label, but assistive technologies will interpret it as a selectable label instead of a tab, which can be confusing.

Additional context See https://github.com/anhosh/egui_dock/pull/345.

Edit: the following has been opened to #8557.

During that PR, I also found out that there is no way to describe the direction (horizontal/vertical) on WidgetType::ResizeHandle, and all splitters are interpreted as "horizontal" in VoiceOver, and also window resizing doesn't work using VoiceOver (it always reports the window resizing handle as a horizontal splitter stuck at 0%). The PR works around this by

rust
let ak_steps = ui.input(|input| {
    input.num_accesskit_action_requests(response.id, accesskit::Action::Increment) as f32
        - input.num_accesskit_action_requests(response.id, accesskit::Action::Decrement) as f32
});
let ak_set_value = ui.input(|input| {
    input
        .accesskit_action_requests(response.id, accesskit::Action::SetValue)
        .find_map(|request| match request.data {
            Some(accesskit::ActionData::NumericValue(value)) => Some(value as f32),
            _ => None,
        })
});
let mut delta = arrow_key_offset.unwrap_or(response.drag_delta());
delta.dim_point += ak_steps * style.separator.arrow_key_step_distance;
if let Some(value) = ak_set_value {
    delta.dim_point += (value.clamp(0.0, 1.0) - split.fraction) * rect.dim_size();
}
apply_separator_delta(split, SeparatorAxis::sep_axis, delta, &style.separator);

if response.double_clicked() {
    split.fraction = 0.5;
}

// Allow assistive technologies to adjust the separator fraction.
let fraction = split.fraction;
let step = style.separator.arrow_key_step_distance / rect.dim_size().max(1.0);
ui.ctx().accesskit_node_builder(response.id, |node| {
    node.set_orientation(accesskit::Orientation::ak_orientation);
    node.set_numeric_value(fraction.into());
    node.set_min_numeric_value(0.0);
    node.set_max_numeric_value(1.0);
    node.set_numeric_value_step(step.into());
    node.add_action(accesskit::Action::Increment);
    node.add_action(accesskit::Action::Decrement);
    node.add_action(accesskit::Action::SetValue);
});