feat(html): add aria state helpers
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-03 18:34:00 +00:00
parent a7433675ba
commit 30f64a3d59
3 changed files with 51 additions and 1 deletions

View file

@ -39,7 +39,7 @@ This builds a Header-Content-Footer layout with semantic HTML elements (`<header
| Path | Purpose |
|------|---------|
| `node.go` | `Node` interface and all node types: `El`, `Text`, `Raw`, `If`, `Unless`, `Each`, `EachSeq`, `Switch`, `Entitled`, plus `AriaLabel`, `Alt`/`AltText`, `AriaDisabled`, `TabIndex`, and `AutoFocus` helpers |
| `node.go` | `Node` interface and all node types: `El`, `Text`, `Raw`, `If`, `Unless`, `Each`, `EachSeq`, `Switch`, `Entitled`, plus `AriaLabel`, `Alt`/`AltText`, `AriaDisabled`, `AriaPressed`, `AriaSelected`, `TabIndex`, and `AutoFocus` helpers |
| `layout.go` | HLCRF compositor with semantic HTML elements and ARIA roles |
| `responsive.go` | Multi-variant breakpoint wrapper (`data-variant` containers, CSS scoping helpers) |
| `context.go` | Rendering context: identity, locale, entitlements, i18n service |

18
node.go
View file

@ -278,6 +278,24 @@ func AriaDisabled(n Node, disabled bool) Node {
return Attr(n, "aria-disabled", "false")
}
// node.go: AriaPressed sets the aria-pressed attribute on an element node.
// Example: AriaPressed(El("button"), true).
func AriaPressed(n Node, pressed bool) Node {
if pressed {
return Attr(n, "aria-pressed", "true")
}
return Attr(n, "aria-pressed", "false")
}
// node.go: AriaSelected sets the aria-selected attribute on an element node.
// Example: AriaSelected(El("option"), true).
func AriaSelected(n Node, selected bool) Node {
if selected {
return Attr(n, "aria-selected", "true")
}
return Attr(n, "aria-selected", "false")
}
// node.go: TabIndex sets the tabindex attribute on an element node.
// Example: TabIndex(El("button"), 0).
func TabIndex(n Node, index int) Node {

View file

@ -411,6 +411,38 @@ func TestAriaDisabledHelper(t *testing.T) {
}
}
func TestAriaPressedHelper(t *testing.T) {
ctx := NewContext()
pressed := AriaPressed(El("button", Raw("menu")), true)
gotPressed := pressed.Render(ctx)
if !strings.Contains(gotPressed, `aria-pressed="true"`) {
t.Errorf("AriaPressed(true) = %q, want aria-pressed=\"true\"", gotPressed)
}
released := AriaPressed(El("button", Raw("menu")), false)
gotReleased := released.Render(ctx)
if !strings.Contains(gotReleased, `aria-pressed="false"`) {
t.Errorf("AriaPressed(false) = %q, want aria-pressed=\"false\"", gotReleased)
}
}
func TestAriaSelectedHelper(t *testing.T) {
ctx := NewContext()
selected := AriaSelected(El("option", Raw("menu")), true)
gotSelected := selected.Render(ctx)
if !strings.Contains(gotSelected, `aria-selected="true"`) {
t.Errorf("AriaSelected(true) = %q, want aria-selected=\"true\"", gotSelected)
}
unselected := AriaSelected(El("option", Raw("menu")), false)
gotUnselected := unselected.Render(ctx)
if !strings.Contains(gotUnselected, `aria-selected="false"`) {
t.Errorf("AriaSelected(false) = %q, want aria-selected=\"false\"", gotUnselected)
}
}
func TestTabIndexHelper(t *testing.T) {
ctx := NewContext()
node := TabIndex(El("button", Raw("action")), -1)