Skip to content

Comments

Implement remaining W3C HTML global attributes#257

Merged
jverkoey merged 12 commits intomainfrom
claude/implement-w3c-modifiers-011CUtjkxxUYQtFP2dB22Lay
Nov 8, 2025
Merged

Implement remaining W3C HTML global attributes#257
jverkoey merged 12 commits intomainfrom
claude/implement-w3c-modifiers-011CUtjkxxUYQtFP2dB22Lay

Conversation

@jverkoey
Copy link
Collaborator

@jverkoey jverkoey commented Nov 7, 2025

This commit implements 25 W3C global HTML attributes as ViewModifiers, completing the full suite of remaining global attributes from the HTML specification. Each modifier balances W3C idioms with SwiftUI conventions to provide a familiar experience for SwiftUI developers.

New modifiers added:

  • accesskey(_:) - Keyboard shortcuts for element activation
  • autocapitalize(_:) - Text capitalization control with enum
  • autofocus(_:) - Page load focus control
  • contenteditable(_:) - Content editability with enum/bool support
  • direction(_:) - Text directionality (ltr, rtl, auto)
  • draggable(_:) - Drag and drop support
  • enterKeyHint(_:) - Virtual keyboard enter key hints
  • hidden(_:) - Element visibility with state support
  • inert(_:) - Non-interactive element marking
  • inputMode(_:) - Virtual keyboard type hints
  • customElement(_:) - Custom element support (is attribute)
  • Microdata support (itemscope, itemtype, itemid, itemprop, itemref)
  • nonce(_:) - Content Security Policy nonce
  • popover(_:) - Popover element support with state
  • slot(_:) - Shadow DOM slot assignment
  • spellcheck(_:) - Spell checking control
  • inlineStyle(_:) - Inline CSS (style attribute)
  • tabIndex(_:) / focusable() - Focus and keyboard navigation
  • tooltip(_:) - Advisory information (title attribute)
  • translatable(_:) - Translation control
  • writingSuggestions(_:) - Browser writing suggestions

Updated AttributeModifier.GlobalAttribute enum with all new cases.

Updated documentation in SlipstreamForWebDevelopers.md with a new "Global attributes" section mapping W3C attributes to Slipstream modifiers.

Implementation follows established patterns using AttributeModifier and ConditionalAttributeModifier for consistent behavior across the codebase.

Part of #27

@jverkoey jverkoey enabled auto-merge (squash) November 8, 2025 23:45
claude added 12 commits November 8, 2025 23:47
This commit implements 25 W3C global HTML attributes as ViewModifiers,
completing the full suite of remaining global attributes from the HTML
specification. Each modifier balances W3C idioms with SwiftUI conventions
to provide a familiar experience for SwiftUI developers.

New modifiers added:
- accesskey(_:) - Keyboard shortcuts for element activation
- autocapitalize(_:) - Text capitalization control with enum
- autofocus(_:) - Page load focus control
- contenteditable(_:) - Content editability with enum/bool support
- direction(_:) - Text directionality (ltr, rtl, auto)
- draggable(_:) - Drag and drop support
- enterKeyHint(_:) - Virtual keyboard enter key hints
- hidden(_:) - Element visibility with state support
- inert(_:) - Non-interactive element marking
- inputMode(_:) - Virtual keyboard type hints
- customElement(_:) - Custom element support (is attribute)
- Microdata support (itemscope, itemtype, itemid, itemprop, itemref)
- nonce(_:) - Content Security Policy nonce
- popover(_:) - Popover element support with state
- slot(_:) - Shadow DOM slot assignment
- spellcheck(_:) - Spell checking control
- inlineStyle(_:) - Inline CSS (style attribute)
- tabIndex(_:) / focusable() - Focus and keyboard navigation
- tooltip(_:) - Advisory information (title attribute)
- translatable(_:) - Translation control
- writingSuggestions(_:) - Browser writing suggestions

Updated AttributeModifier.GlobalAttribute enum with all new cases.

Updated documentation in SlipstreamForWebDevelopers.md with a new
"Global attributes" section mapping W3C attributes to Slipstream modifiers.

Implementation follows established patterns using AttributeModifier and
ConditionalAttributeModifier for consistent behavior across the codebase.
Move all enum types outside of View protocol extensions to resolve Swift
compilation errors. Swift does not allow nested types in protocol extensions.

Fixed enums:
- Autocapitalize (in View+autocapitalize.swift)
- Contenteditable (in View+contenteditable.swift)
- TextDirection (in View+dir.swift)
- EnterKeyHint (in View+enterkeyhint.swift)
- HiddenState (in View+hidden.swift)
- InputMode (in View+inputmode.swift)
- PopoverState (in View+popover.swift)
- TranslateMode (in View+translate.swift)

All enums are now top-level types with @available(iOS 17.0, macOS 14.0, *)
annotations, making them accessible while maintaining the same API surface.
Rename the accesskey(_:) modifier to keyboardShortcut(_:) to better align
with SwiftUI naming conventions. SwiftUI uses keyboardShortcut for similar
functionality, making this name more familiar to SwiftUI developers.

The modifier still sets the HTML accesskey attribute internally, maintaining
full W3C compatibility while providing a more intuitive API.

Updated:
- View+accesskey.swift: Renamed function and updated example
- SlipstreamForWebDevelopers.md: Updated documentation table
Rename the enterKeyHint(_:) modifier to submitLabel(_:) to better align
with SwiftUI naming conventions. SwiftUI uses submitLabel(_:) for controlling
the appearance of the return key on virtual keyboards.

The modifier still sets the HTML enterkeyhint attribute internally, maintaining
full W3C compatibility while providing a more familiar API for SwiftUI developers.

Updated:
- View+enterkeyhint.swift: Renamed function and parameter, updated example
- SlipstreamForWebDevelopers.md: Updated documentation table
Rename modifiers to better align with SwiftUI naming conventions:

1. inert(_:) → allowsHitTesting(_:)
   - Inverted logic: allowsHitTesting(false) sets the inert attribute
   - allowsHitTesting(true) is the default (no inert attribute)
   - Matches SwiftUI's allowsHitTesting modifier semantics

2. inputMode(_:) → keyboardType(_:)
   - Renamed InputMode enum to KeyboardType
   - Matches SwiftUI's keyboardType modifier
   - Still sets the HTML inputmode attribute internally

Updated:
- View+inert.swift: Renamed to allowsHitTesting with inverted logic
- View+inputmode.swift: Renamed to keyboardType, enum to KeyboardType
- SlipstreamForWebDevelopers.md: Updated documentation table
Rename all microdata modifiers to use proper Swift camelCase naming:
- itemscope(_:) → itemScope(_:)
- itemtype(_:) → itemType(_:)
- itemid(_:) → itemID(_:)
- itemprop(_:) → itemProp(_:)
- itemref(_:) → itemRef(_:)

All modifiers still set the correct HTML attributes (itemscope, itemtype, etc.)
internally while providing a more Swift-idiomatic API.

Updated:
- View+microdata.swift: All function names and examples
- SlipstreamForWebDevelopers.md: Updated documentation table
Add test coverage for all 21 new W3C global attribute modifiers:

Keyboard & Input:
- KeyboardShortcutTests: Tests for keyboardShortcut(_:) modifier
- AutocapitalizeTests: Tests for all autocapitalize modes (none, sentences, words, characters)
- AutofocusTests: Tests for autofocus(_:) with boolean values
- SubmitLabelTests: Tests for all submitLabel cases (enter, done, go, next, previous, search, send)
- KeyboardTypeTests: Tests for all keyboardType cases (none, text, decimal, numeric, tel, search, email, url)

Content & Display:
- ContenteditableTests: Tests for contenteditable with enum and boolean values
- DirectionTests: Tests for direction(_:) with ltr, rtl, and auto
- HiddenTests: Tests for hidden(_:) with boolean and HiddenState enum
- TranslatableTests: Tests for translatable(_:) with enum and boolean values
- TooltipTests: Tests for tooltip(_:) modifier

Interaction:
- AllowsHitTestingTests: Tests for allowsHitTesting(_:) with inverted inert logic
- DraggableTests: Tests for draggable(_:) modifier
- PopoverTests: Tests for popover(_:) with PopoverState and boolean
- TabIndexTests: Tests for tabIndex(_:) and focusable() convenience method

Microdata:
- MicrodataTests: Comprehensive tests for itemScope, itemType, itemID, itemProp, itemRef, and combined usage

Miscellaneous:
- NonceTests: Tests for nonce(_:) modifier
- SlotTests: Tests for slot(_:) modifier
- SpellcheckTests: Tests for spellcheck(_:) modifier
- InlineStyleTests: Tests for inlineStyle(_:) modifier
- CustomElementTests: Tests for customElement(_:) modifier
- WritingSuggestionsTests: Tests for writingSuggestions(_:) modifier

All tests follow existing Slipstream test patterns and verify correct HTML attribute generation.
The file SlotTests.swift conflicts with the existing W3C/SlotTests.swift
that tests the <slot> element. Renamed to SlotAttributeTests.swift to test
the slot attribute specifically.
Remove the boolean overload of hidden(_:) to avoid conflict with the
existing TailwindCSS hidden() modifier. Now only the HiddenState version
exists: hidden(.hidden) or hidden(.untilFound).

The two modifiers serve different purposes:
- TailwindCSS hidden(): Visual hiding via CSS display property
- W3C hidden(_:): Semantic hiding via HTML hidden attribute

Users should use:
- TailwindCSS .hidden() for CSS-based visual hiding
- W3C .hidden(.hidden) for semantic HTML attribute hiding
- W3C .hidden(.untilFound) for hidden-until-found state

Updated:
- View+hidden.swift: Removed boolean overload, clarified documentation
- HiddenTests.swift: Removed boolean tests, kept only HiddenState tests
- SlipstreamForWebDevelopers.md: Clarified the difference
Update test expectations to match actual HTML rendering:
- Change multiline expectations to single-line for elements with text content
- Fix boolean attribute expectations (itemscope without ="")
- Update KeyboardShortcutTests, SlotAttributeTests, MicrodataTests,
  CustomElementTests, TooltipTests, and NonceTests

The HTML output is semantically correct, just formatted differently
than initially expected.
Update remaining tests to expect single-line HTML output:
- KeyboardShortcutTests
- SlotAttributeTests
- TooltipTests

All tests now match the actual rendering behavior.
Boolean attributes now render without ="" suffix (HTML5 standard):
- autofocus="" → autofocus
- inert="" → inert
- hidden="" → hidden (when using .hidden state)

Also fixed combinedMicrodata test to expect multi-line output.

Updated tests:
- AllowsHitTestingTests: inert without =""
- HiddenTests: hidden without =""
- AutofocusTests: autofocus without =""
- MicrodataTests: combinedMicrodata multi-line format
@jverkoey jverkoey force-pushed the claude/implement-w3c-modifiers-011CUtjkxxUYQtFP2dB22Lay branch from 9cad748 to ace0ccb Compare November 8, 2025 23:47
@jverkoey jverkoey merged commit 142b034 into main Nov 8, 2025
2 checks passed
@jverkoey jverkoey deleted the claude/implement-w3c-modifiers-011CUtjkxxUYQtFP2dB22Lay branch November 8, 2025 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants