Skip to content

Commit

Permalink
fix accesibility and keyboard navigation issues in examples (#1433)
Browse files Browse the repository at this point in the history
* fix accesibility and keyboard navigation issues in examples

* fix review comments

* remove redundant aria attributes, remove redundant autofocus

* rework progress bar demo's accesibility

* rework tabs HATEOS example to be more ARIA compliant

* rework tabs _hyperscript example to be ARIA compliant
  • Loading branch information
Renerick authored Jun 30, 2023
1 parent 1561a7d commit 18aa247
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 187 deletions.
20 changes: 11 additions & 9 deletions www/content/examples/animations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title = "Animations"
template = "demo.html"
+++

htmx is designed to allow you to use [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions)
to add smooth animations and transitions to your web page using only CSS and HTML. Below are a few examples of
various animation techniques.
Expand Down Expand Up @@ -42,7 +42,7 @@ This div will poll every second and will get replaced with new content which cha
Color Swap Demo
</div>
```

Because the div has a stable id, `color-demo`, htmx will structure the swap such that a CSS transition, defined on the
`.smooth` class, applies to the style update from `red` to `blue`, and smoothly transitions between them.

Expand Down Expand Up @@ -71,15 +71,15 @@ Because the div has a stable id, `color-demo`, htmx will structure the swap such

### Smooth Progress Bar

The [Progress Bar](@/examples/progress-bar.md) demo uses this basic CSS animation technique as well, by updating the `length`
The [Progress Bar](@/examples/progress-bar.md) demo uses this basic CSS animation technique as well, by updating the `length`
property of a progress bar element, allowing for a smooth animation.

## Swap Transitions {#swapping}

### Fade Out On Swap

If you want to fade out an element that is going to be removed when the request ends, you want to take advantage
of the `htmx-swapping` class with some CSS and extend the swap phase to be long enough for your animation to
of the `htmx-swapping` class with some CSS and extend the swap phase to be long enough for your animation to
complete. This can be done like so:

```html
Expand Down Expand Up @@ -178,7 +178,7 @@ is a form that on submit will change its look to indicate that a request is bein
transition: opacity 300ms linear;
}
</style>
<form hx-post="/name">
<form hx-post="/name" hx-swap="outerHTML">
<label>Name:</label><input name="name"><br/>
<button>Submit</button>
</form>
Expand All @@ -193,10 +193,12 @@ is a form that on submit will change its look to indicate that a request is bein
}
</style>

<form hx-post="/name">
<div aria-live="polite">
<form hx-post="/name" hx-swap="outerHTML">
<label>Name:</label><input name="name"><br/>
<button>Submit</button>
</form>
</div>

<script>
onPost("/name", function(){ return "Submitted!"; });
Expand Down Expand Up @@ -238,14 +240,14 @@ the transition time. This avoids flickering that can happen if the transition i
### Using the View Transition API {#view-transitions}

htmx provides access to the new [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
via the `transition` option of the [`hx-swap`](/attributes/hx-swap) attribute.
via the `transition` option of the [`hx-swap`](/attributes/hx-swap) attribute.

Below is an example of a swap that uses a view transition. The transition is tied to the outer div via a
Below is an example of a swap that uses a view transition. The transition is tied to the outer div via a
`view-transition-name` property in CSS, and that transition is defined in terms of `::view-transition-old`
and `::view-transition-new`, using `@keyframes` to define the animation. (Fuller details on the View Transition
API can be found on the [Chrome Developer Page](https://developer.chrome.com/docs/web-platform/view-transitions/) on them.)

The old content of this transition should slide out to the left and the new content should slide in from the right.
The old content of this transition should slide out to the left and the new content should slide in from the right.

Note that, as of this writing, the visual transition will only occur on Chrome 111+, but more browsers are expected to
implement this feature in the near future.
Expand Down
18 changes: 9 additions & 9 deletions www/content/examples/bulk-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
title = "Bulk Update"
template = "demo.html"
+++
This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is

This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is
accomplished by putting a form around a table, with checkboxes in the table, and then including the checked
values in `PUT`'s to two different endpoints: `activate` and `deactivate`:

```html
<div hx-include="#checked-contacts" hx-target="#tbody">
<a class="btn" hx-put="/activate">Activate</a>
<a class="btn" hx-put="/deactivate">Deactivate</a>
<button class="btn" hx-put="/activate">Activate</button>
<button class="btn" hx-put="/deactivate">Deactivate</button>
</div>

<form id="checked-contacts">
Expand Down Expand Up @@ -90,7 +90,7 @@ You can see a working example of this code below.
}
}
}()

function getIds(params) {
if(params['ids']) {
if(Array.isArray(params['ids'])) {
Expand Down Expand Up @@ -126,7 +126,7 @@ You can see a working example of this code below.

// templates
function displayUI(contacts) {
return `<h3>Select Rows And Activate Or Deactivate Below<h3>
return `<h3>Select Rows And Activate Or Deactivate Below</h3>
<form id="checked-contacts">
<table>
<thead>
Expand All @@ -145,11 +145,11 @@ You can see a working example of this code below.
<br/>
<br/>
<div hx-include="#checked-contacts" hx-target="#tbody">
<a class="btn" hx-put="/activate">Activate</a>
<a class="btn" hx-put="/deactivate">Deactivate</a>
<button class="btn" hx-put="/activate">Activate</button>
<button class="btn" hx-put="/deactivate">Deactivate</button>
</div>`
}

function displayTable(ids, contacts, action) {
var txt = "";
for (var i = 0; i < contacts.length; i++) {
Expand Down
16 changes: 8 additions & 8 deletions www/content/examples/click-to-edit.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The click to edit pattern provides a way to offer inline editing of all or part
</div>
<button class="btn">Submit</button>
<button class="btn" hx-get="/contact/1">Cancel</button>
</form>
</form>
```

* The form issues a `PUT` back to `/contacts/1`, following the usual REST-ful pattern.
Expand Down Expand Up @@ -75,18 +75,18 @@ The click to edit pattern provides a way to offer inline editing of all or part
function formTemplate(contact) {
return `<form hx-put="/contact/1" hx-target="this" hx-swap="outerHTML">
<div>
<label>First Name</label>
<input type="text" name="firstName" value="${contact.firstName}">
<label for="firstName">First Name</label>
<input autofocus type="text" id="firstName" name="firstName" value="${contact.firstName}">
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" name="lastName" value="${contact.lastName}">
<label for="lastName">Last Name</label>
<input type="text" id="lastName" name="lastName" value="${contact.lastName}">
</div>
<div class="form-group">
<label>Email Address</label>
<input type="email" name="email" value="${contact.email}">
<label for="email">Email Address</label>
<input type="email" id="email" name="email" value="${contact.email}">
</div>
<button class="btn">Submit</button>
<button class="btn" type="submit">Submit</button>
<button class="btn" hx-get="/contact/1">Cancel</button>
</form>`
}
Expand Down
20 changes: 10 additions & 10 deletions www/content/examples/click-to-load.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ the final row:
```html
<tr id="replaceMe">
<td colspan="3">
<button class='btn' hx-get="/contacts/?page=2"
hx-target="#replaceMe"
<button class='btn' hx-get="/contacts/?page=2"
hx-target="#replaceMe"
hx-swap="outerHTML">
Load More Agents... <img class="htmx-indicator" src="/img/bars.svg">
</button>
</td>
</tr>
</tr>
```

This row contains a button that will replace the entire row with the next page of
Expand Down Expand Up @@ -48,31 +48,31 @@ results (which will contain a button to load the *next* page of results). And s
}
}
}()

// routes
init("/demo", function(request, params){
var contacts = dataStore.contactsForPage(1)
return tableTemplate(contacts)
});

onGet(/\/contacts.*/, function(request, params){
var page = parseInt(params['page']);
var contacts = dataStore.contactsForPage(page)
return rowsTemplate(page, contacts);
});

// templates
function tableTemplate(contacts) {
return `<table><thead><tr><th>Name</th><th>Email</th><th>ID</th></tr></thead><tbody>
${rowsTemplate(1, contacts)}
</tbody></table>`
}

function rowsTemplate(page, contacts) {
var txt = "";
for (var i = 0; i < contacts.length; i++) {
var c = contacts[i];
txt += "<tr><td>" + c.name + "</td><td>" + c.email + "</td><td>" + c.id + "</td></tr>\n";
txt += `<tr><td>${c.name}</td><td>${c.email}</td><td>${c.id}</td></tr>\n`;
}
txt += loadMoreRow(page);
return txt;
Expand All @@ -82,8 +82,8 @@ results (which will contain a button to load the *next* page of results). And s
return `<tr id="replaceMe">
<td colspan="3">
<center>
<button class='btn' hx-get="/contacts/?page=${page + 1}"
hx-target="#replaceMe"
<button class='btn' hx-get="/contacts/?page=${page + 1}"
hx-target="#replaceMe"
hx-swap="outerHTML">
Load More Agents... <img class="htmx-indicator" src="/img/bars.svg">
</button>
Expand Down
30 changes: 15 additions & 15 deletions www/content/examples/inline-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ When a request occurs, it will return a partial to replace the outer div. It mi
<input name="email" hx-post="/contact/email" hx-indicator="#ind" value="[email protected]">
<img id="ind" src="/img/bars.svg" class="htmx-indicator"/>
<div class='error-message'>That email is already taken. Please enter another email.</div>
</div>
</div>
```

Note that this div is annotated with the `error` class and includes an error message element.
Expand Down Expand Up @@ -92,7 +92,7 @@ Below is a working demo of this example. The only email that will be accepted i
onPost("/contact", function(request, params){
return formTemplate();
});

onPost(/\/contact\/email.*/, function(request, params){
var email = params['email'];
if(!/\S+@\S+\.\S+/.test(email)) {
Expand All @@ -103,38 +103,38 @@ Below is a working demo of this example. The only email that will be accepted i
return emailInputTemplate(email);
}
});

// templates
function demoTemplate() {

return `<h3>Signup Form</h3><p>Enter an email into the input below and on tab out it will be validated. Only "[email protected]" will pass.</p> ` + formTemplate();
}

function formTemplate() {
return `<form hx-post="/contact">
<div hx-target="this" hx-swap="outerHTML">
<label>Email Address</label>
<input name="email" hx-post="/contact/email" hx-indicator="#ind">
<label for="email">Email Address</label>
<input name="email" id="email" hx-post="/contact/email" hx-indicator="#ind">
<img id="ind" src="/img/bars.svg" class="htmx-indicator"/>
</div>
<div class="form-group">
<label>First Name</label>
<input type="text" class="form-control" name="firstName">
<label for="firstName">First Name</label>
<input type="text" class="form-control" name="firstName" id="firstName">
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" name="lastName">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" name="lastName" id="lastName">
</div>
<button class="btn btn-default" disabled>Submit</button>
<button type='submit' class="btn btn-default" disabled>Submit</button>
</form>`;
}

function emailInputTemplate(val, errorMsg) {
return `<div hx-target="this" hx-swap="outerHTML" class="${errorMsg ? "error" : "valid"}">
<label>Email Address</label>
<input name="email" hx-post="/contact/email" hx-indicator="#ind" value="${val}">
<input name="email" hx-post="/contact/email" hx-indicator="#ind" value="${val}" aria-invalid="${!!errorMsg}">
<img id="ind" src="/img/bars.svg" class="htmx-indicator"/>
${errorMsg ? ("<div class='error-message'>" + errorMsg + "</div>") : ""}
${errorMsg ? (`<div class='error-message' >${errorMsg}</div>`) : ""}
</div>`;
}
</script>
4 changes: 2 additions & 2 deletions www/content/examples/lazy-load.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ img {
init("/demo", function(request, params){
return lazyTemplate();
});

onGet("/graph", function(request, params){
return "<img alt='Tokyo Climate' src='/img/tokyo.png'>";
});

// templates
function lazyTemplate(page) {
return `<div hx-get="/graph" hx-trigger="load">
Expand Down
Loading

0 comments on commit 18aa247

Please sign in to comment.