Christian Tanul ee4ef5f18d
update /patterns & /help page (#3513)
* fix autofocus on mobile search bar

* improve pattern documentation structure and titles

- inline-validation.md → active-validation.md
- bulk-update.md → bulk-actions.md
- delete-row.md → delete-in-place.md
- sortable.md → drag-to-reorder.md
- click-to-edit.md → edit-in-place.md
- value-select.md → linked-selects.md
- reset-user-input.md → reset-on-submit.md
- Merged tabs-hateoas.md and tabs-javascript.md into single tabs.md
- Removed obsolete files:
- file-upload-input.md (merged into file-upload.md)
- web-components.md (content moved to /docs - not a pattern)
- Refreshed titles and descriptions
- Updated icons for better visual consistency
- Disabled interactive demos:
- Commented out {{ demo_environment() }} and demo code blocks in: animations, click-to-load, infinite-scroll, file-upload, bulk-actions, drag-to-reorder, edit-in-place, active-search
- Minor formatting cleanup across multiple pattern files

* update /help page
2025-11-10 19:56:53 -07:00

7.4 KiB

+++ title = "Tabs" template = "demo.html" +++ Switch between content panels. Two approaches: server controls tab state, or JavaScript does.

Server-Driven (HATEOAS)

The server controls which tab is selected. This follows HATEOAS (Hypertext As The Engine Of Application State) - the server returns complete UI state with each response.

<!-- Initial container -->
<div id="tabs" hx-get="/tab1" hx-trigger="load"></div>
<!-- Server returns this for each tab click -->
<div role="tablist">
  <button hx-get="/tab1" role="tab" aria-selected="true">Tab 1</button>
  <button hx-get="/tab2" role="tab" aria-selected="false">Tab 2</button>
  <button hx-get="/tab3" role="tab" aria-selected="false">Tab 3</button>
</div>

<div role="tabpanel">
  Tab content here...
</div>

Client-Side

JavaScript handles tab selection. Server returns content only. Uses aria-selected attribute to control styling.

<div role="tablist" 
     hx-target:inherited="#tab-contents"
     hx-on:htmx-after-on-load="
       document.querySelector('[aria-selected=true]').setAttribute('aria-selected', 'false');
       event.target.setAttribute('aria-selected', 'true');
     ">
  <button role="tab" hx-get="/tab1" aria-selected="true">Tab 1</button>
  <button role="tab" hx-get="/tab2" aria-selected="false">Tab 2</button>
  <button role="tab" hx-get="/tab3" aria-selected="false">Tab 3</button>
</div>

<div id="tab-contents" role="tabpanel" hx-get="/tab1" hx-trigger="load"></div>

Server returns just the content:

<p>Your tab content...</p>