Start with the element
Start with the element in the Accessibility guide.
Use the element that has the behavior. A <button> is focusable, activates on Enter and Space, and has
the button role. A <div onClick> has none of that:
src/native.tsxtsx
import { useStore } from "@shadow-js/core";
export function Saves() {
const [saved, setSaved] = useStore(0);
return (
<section aria-labelledby="saves-title">
<h2 id="saves-title">Saves</h2>
<button type="button" onClick={() => setSaved((n) => n + 1)}>
Save
</button>
<p role="status">{saved()} saved</p>
</section>
);
}
When you must use a non-interactive element as a control, you take on everything the native one does:
role, tabIndex={0}, Enter and Space handling, a disabled state. Prefer changing the element.
Other semantic habits that need no framework support: one <h1> per page and headings in order,
landmarks (<main>, <nav>, <header>, <footer>) instead of role on div, <ul>/<ol> for lists,
<table> with <th scope> for data, <fieldset> and <legend> for groups of controls, alt on
every <img> (empty for decoration), and lang on <html>.