[]previous and next page

Start with the element

Start with the element in the Accessibility guide.

For agentsUpdated

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>.