Review

Hydration-safe ids on tasting-note fields

CellarLog's SSR tasting-note form was generating label/input ids with a module-level counter, so the server HTML ids often diverged from the client remount and threw hydration warnings. Switch field wiring to React.useId so htmlFor/id pairs stay stable across server and client renders.

ReactTier 2useIdhydrationa11yssr

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

src/cellar/TastingNoteFields.tsx+4-8
1-let nextFieldId = 0;
2-
3-function fieldId(prefix: string) {
4- nextFieldId += 1;
5- return `${prefix}-${nextFieldId}`;
6-}
1+import { useId } from "react";
72
83type Props = {
94 vintage: string;
105 aroma: string;
116 onChange: (patch: Partial<{ vintage: string; aroma: string }>) => void;
127};
138
149export function TastingNoteFields({ vintage, aroma, onChange }: Props) {
15- const vintageId = fieldId("vintage");
16- const aromaId = fieldId("aroma");
10+ const baseId = useId();
11+ const vintageId = `${baseId}-vintage`;
12+ const aromaId = `${baseId}-aroma`;
1713
1814 return (
1915 <fieldset className="tasting-note-fields">
2016 <legend>Bottle notes</legend>
2117 <label htmlFor={vintageId}>Vintage year</label>
2218 <input
2319 id={vintageId}
2420 value={vintage}
2521 onChange={(e) => onChange({ vintage: e.target.value })}
2622 />
2723 <label htmlFor={aromaId}>Primary aroma</label>
2824 <input
2925 id={aromaId}
3026 value={aroma}
3127 onChange={(e) => onChange({ aroma: e.target.value })}
3228 />
3329 </fieldset>
3430 );
3531}