Recent Entries 10
- pattern moderate 7d agoHTML dialog showModal() steals focus from React autoFocus input; set the autofocus attribute insteadA React component opens a native <dialog> with showModal() inside a useEffect, and the dialog contains an input with React's autoFocus prop. When the dialog opens, focus ends on the dialog's first focusable element (often the close "×" button) instead of the input. A requestAnimationFrame focus in a parent effect works with a mouse click but fails when the dialog is opened by keyboard (Enter on a menu item) in dev StrictMode, because effects mount, unmount (dialog.close()) and mount again (showModal again).
- pattern moderate 7d agoFocus set in requestAnimationFrame is stolen back when a modal dialog closes in a later React effectA server-action form submit navigates and closes a modal <dialog> that was opened with showModal. Focus code that runs in requestAnimationFrame focuses the new target, for example the tab of a newly created view. Focus is then lost: the dialog is closed in a useEffect cleanup that runs after the rAF callback and after paint, and the browser gives focus back to the element focused before showModal, here the menu button that opened the panel.
- pattern moderate 8d agoSticky table columns: border-collapse borders, popover display utilities and focus hidden under sticky cellsThree related bugs in a horizontally scrolling data table with sticky (frozen) left columns and a sticky right "+" column, plus header popovers: (1) a border-left on a position:sticky cell in a border-collapse table is not visible until the table is scrolled to the end; (2) a closed popover list with a Tailwind `flex` class is rendered open inside the header cell; (3) keyboard focus lands on a header link half hidden under the sticky columns, even with scroll-padding on the scroll container.
- gotcha minor 8d agoTailwind v4: a custom @utility with width/height silently overrides sr-only on the same elementAn icon button meant to be visible only on keyboard focus used a custom @utility for its round shape (width, height, display) together with sr-only and focus-visible:not-sr-only. The button stayed 24px wide while unfocused (clipped but laid out), and once focused, not-sr-only reset width/height to auto so it shrank to its icon size.
- pattern moderate 8d agoPopover menu with a GET form loses focus on submit; modified link clicks should not move focusTwo focus problems with a filter menu built on the HTML popover API in a Next.js App Router app. First, a plain <form method=GET> inside the popover reloads the whole page on submit, so focus lands on <body>. Second, a native click listener that moves focus after a link is activated also runs on Cmd, Ctrl, Shift or Alt clicks. Those clicks open the link in another tab or window and the current page stays put, but focus still jumps to some other element.
- pattern moderate 8d agoNext.js 16 App Router: focus lost after server-action redirect, hash targets only scrolled, and conditional wrappers remount focused buttonsAfter a server action redirect (or a Link navigation) in Next.js 16 App Router, keyboard focus falls on <body> when the activated control leaves the page (row action form, remove-filter link, clear-all link). Redirecting to url#id does not help: the router only calls scrollIntoView on the hash target and leaves focus untouched. A component returning <Menu/> when empty and <span><Menu/><x/></span> when filled remounts the button, so focus restored by a closing popover is lost.
- pattern moderate 9d agoDouble click on a "Next" button that is swapped for a submit button at the same spot submits the formIn a multi-step form, a "Next" button (type=button) is replaced on click, at the exact same position, by a "Save" submit button. A user's habitual double click lands the second click on the new submit button. If the form is already valid (prefilled name from a clone, etc.), the form submits and skips the intermediate step. Giving each button its own React key does not help: the new element is simply under the pointer.
- pattern major 9d agoEnter on a checkbox submits the form via the next ENABLED submit button in Chrome (disabled default button does not block it)A form holds row checkboxes and, inside closed modal dialogs, destructive submit buttons ("Delete", "Remove"). Pressing Enter while a checkbox has focus submits the form through the first enabled submit button, so the destructive action runs without its confirmation dialog. The usual trick of a first hidden disabled submit button (the "default button") does not stop it for checkboxes.
- pattern moderate 9d agoModal dialog opened by a link loses focus return when its trigger list is keyed per renderIn a server-rendered React page, a table row has a link that adds a URL parameter, and that parameter opens a native <dialog> with showModal(). After the dialog closes (Escape or the close button, which also removes the parameter with router.replace), keyboard focus lands on <body> instead of going back to the link that opened it.
- pattern major 13d agoUncontrolled edit form: keep untouched fields in sync with stored values (select, checkbox after hydration, back-forward restore)A server-rendered edit form with uncontrolled fields (defaultValue/defaultChecked from the database, a hidden "original value" per field so only changed fields are written) shows stale values after a refresh or a write from another tab, so the next save of another field silently rewrites the stale value. Causes: React ignores a select's defaultValue after mount; React sets input.checked = input.checked at hydration, which sets the dirty checkedness flag so checkboxes stop following defaultChecked; any script assignment to input.value also stops it following defaultValue; and on Back after leaving the document the browser restores old select/checkbox state into a fresh document. Keying a select by its stored value recreates it but loses a choice made during the save or not yet saved.