fix tabIndex default for interactive elements per spec

interactive elements (input, button, a, select, textarea, iframe)
default to 0 when tabindex attribute is absent; others default to -1.
also add TODO for hidden "until-found" tristate.
This commit is contained in:
egrs
2026-02-18 13:13:12 +01:00
parent 9e4db89521
commit 07a87dfba7
2 changed files with 26 additions and 1 deletions

View File

@@ -30,10 +30,27 @@
i1.tabIndex = 10; i1.tabIndex = 10;
testing.expectEqual(10, i1.tabIndex); testing.expectEqual(10, i1.tabIndex);
// Non-interactive elements default to -1
const d3 = document.getElementById('d3'); const d3 = document.getElementById('d3');
testing.expectEqual(-1, d3.tabIndex); testing.expectEqual(-1, d3.tabIndex);
d3.tabIndex = 0; d3.tabIndex = 0;
testing.expectEqual(0, d3.tabIndex); testing.expectEqual(0, d3.tabIndex);
// Interactive elements default to 0 per spec
const input = document.createElement('input');
testing.expectEqual(0, input.tabIndex);
const button = document.createElement('button');
testing.expectEqual(0, button.tabIndex);
const a = document.createElement('a');
testing.expectEqual(0, a.tabIndex);
const select = document.createElement('select');
testing.expectEqual(0, select.tabIndex);
const textarea = document.createElement('textarea');
testing.expectEqual(0, textarea.tabIndex);
} }
</script> </script>

View File

@@ -342,6 +342,8 @@ pub fn click(self: *HtmlElement, page: *Page) !void {
try page._event_manager.dispatch(self.asEventTarget(), event); try page._event_manager.dispatch(self.asEventTarget(), event);
} }
// TODO: Per spec, hidden is a tristate: true | false | "until-found".
// We only support boolean for now; "until-found" would need bridge union support.
pub fn getHidden(self: *HtmlElement) bool { pub fn getHidden(self: *HtmlElement) bool {
return self.asElement().getAttributeSafe(comptime .wrap("hidden")) != null; return self.asElement().getAttributeSafe(comptime .wrap("hidden")) != null;
} }
@@ -355,7 +357,13 @@ pub fn setHidden(self: *HtmlElement, hidden: bool, page: *Page) !void {
} }
pub fn getTabIndex(self: *HtmlElement) i32 { pub fn getTabIndex(self: *HtmlElement) i32 {
const attr = self.asElement().getAttributeSafe(comptime .wrap("tabindex")) orelse return -1; const attr = self.asElement().getAttributeSafe(comptime .wrap("tabindex")) orelse {
// Per spec, interactive/focusable elements default to 0 when tabindex is absent
return switch (self._type) {
.anchor, .area, .button, .input, .select, .textarea, .iframe => 0,
else => -1,
};
};
return std.fmt.parseInt(i32, attr, 10) catch -1; return std.fmt.parseInt(i32, attr, 10) catch -1;
} }