Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
190183f
fix(bulma-ui): name Autocomplete's suggestion list from a surrounding…
allxsmith Oct 9, 2026
1a7b0a8
docs: say the label that names an Autocomplete names its suggestion list
allxsmith Oct 9, 2026
d9c82dd
chore: regenerate
allxsmith Oct 9, 2026
ad46c06
fix(bulma-ui): name Autocomplete's list from a hand-wired Field label…
allxsmith Oct 9, 2026
686e87b
test(bulma-ui): run the list-name matrix over horizontal and hand-wir…
allxsmith Oct 9, 2026
93b59fd
docs: give the horizontal Autocomplete examples' labels an id for the…
allxsmith Oct 9, 2026
1139975
chore: regenerate
allxsmith Oct 9, 2026
bf9d2f5
Merge remote-tracking branch 'origin/main' into gate-fix-998-autocomp…
allxsmith Oct 9, 2026
b47769d
Merge remote-tracking branch 'origin/main' into work-1008-merge
allxsmith Oct 10, 2026
355065b
fix(bulma-ui): name a range Slider's thumbs from a hand-wired Field l…
allxsmith Oct 10, 2026
a70d888
docs: say a hand-wired Field label with an id names range Slider thumbs
allxsmith Oct 10, 2026
fb2c8f1
chore: regenerate
allxsmith Oct 10, 2026
514127f
fix(bulma-ui): say which controls a hand-wired Field label's id reaches
allxsmith Oct 10, 2026
80ea9b9
test(bulma-ui): pin a hand-wired Field label in grouped and addons rows
allxsmith Oct 10, 2026
385f6a4
docs: teach the bestax-form skill to give a hand-wired label an id
allxsmith Oct 10, 2026
db86af2
docs(bulma-ui): add stories for labels that name lists and range thumbs
allxsmith Oct 10, 2026
31f08ef
chore: regenerate
allxsmith Oct 10, 2026
ff8bf90
docs(bulma-ui): wire the Field and Control wrapper stories to their l…
allxsmith Oct 10, 2026
2b31181
Merge remote-tracking branch 'origin/main' into work-1008-merge2
allxsmith Oct 10, 2026
d836b60
chore: regenerate after merging main
allxsmith Oct 10, 2026
07c2a99
fix(bulma-ui): say a label placed in Field.Label reaches no thumbs or…
allxsmith Oct 10, 2026
c38e4a6
docs: say when the bestax-form skill's two hand-wired labels apply
allxsmith Oct 10, 2026
551d4cb
chore: regenerate
allxsmith Oct 10, 2026
9b33d8d
fix(bulma-ui): say the label prop needs wiring to reach thumbs or lis…
allxsmith Oct 10, 2026
d5f4ba6
chore: regenerate
allxsmith Oct 10, 2026
30b7dd2
Merge remote-tracking branch 'origin/main' into gate-fix-998-autocomp…
allxsmith Oct 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions bestax-mcp/data/components/Autocomplete.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@
},
{
"title": "Context-Aware Rendering",
"code": "function example() {\n return (\n <Field horizontal label=\"Fruit\" labelProps={{ htmlFor: 'fruit-field' }}>\n <Field.Body>\n <Field>\n <Autocomplete\n id=\"fruit-field\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{ htmlFor: 'fruit-field', id: 'fruit-field-label' }}\n >\n <Field.Body>\n <Field>\n <Autocomplete\n id=\"fruit-field\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
Comment thread
claude[bot] marked this conversation as resolved.
},
{
Comment thread
claude[bot] marked this conversation as resolved.
"title": "Context-Aware Rendering",
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{ htmlFor: 'fruit-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"search\">\n <Autocomplete\n id=\"fruit-field-control\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{\n htmlFor: 'fruit-field-control',\n id: 'fruit-field-control-label',\n }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"search\">\n <Autocomplete\n id=\"fruit-field-control\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
}
],
"accessibility": "- The `label` prop is automatically associated with the inner text input (`htmlFor` plus a generated `id`, or your own `id` if you pass one), so clicking the label focuses the input and assistive technology announces it. Inside a labeled `Field`, that `Field`'s label names the input the same way.\n- A user-supplied `id` is applied to the inner input (the labellable control), not the wrapper div.\n- Uses `role=\"combobox\"` with `aria-expanded`, which is true only while the list is on screen\n- Has `aria-haspopup=\"listbox\"` and `aria-autocomplete=\"list\"`, and, while the list is on screen, `aria-controls` pointing at it\n- Focus stays in the input, which points `aria-activedescendant` at the highlighted option as the arrow keys move it\n- The list is a `role=\"listbox\"` named by the `label` prop's label. Inside an outer `Field`, or with no `label`, it falls back to `aria-label=\"Suggestions\"`\n- Dropdown items use `role=\"option\"` with `aria-selected`\n- Disabled items have `aria-disabled`\n- The `clearable` clear button is a native button named \"Clear\": `Tab` from the input reaches it, and `Enter` or `Space` clears the input and puts focus back in it\n- Full keyboard navigation support",
"accessibility": "- The `label` prop is automatically associated with the inner text input (`htmlFor` plus a generated `id`, or your own `id` if you pass one), so clicking the label focuses the input and assistive technology announces it. Inside a labeled `Field`, that `Field`'s label names the input instead when it points at it: a `Field` that is not `grouped` or `hasAddons` points it there on its own when the Autocomplete has no `id` and no inner `Field` sits between them, and a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`.\n- A user-supplied `id` is applied to the inner input (the labellable control), not the wrapper div.\n- Uses `role=\"combobox\"` with `aria-expanded`, which is true only while the list is on screen\n- Has `aria-haspopup=\"listbox\"` and `aria-autocomplete=\"list\"`, and, while the list is on screen, `aria-controls` pointing at it\n- Focus stays in the input, which points `aria-activedescendant` at the highlighted option as the arrow keys move it\n- The list is a `role=\"listbox\"` named through `aria-labelledby` by the label that names the input, when that label has an id: the `label` prop's label always has one, and so does a `Field`'s label that the `Field` wires itself. A `Field` label you wire by hand with `labelProps.htmlFor`, which is how a horizontal form names an Autocomplete in an inner `Field`, needs an `id` in its `labelProps` as well. Otherwise the list falls back to `aria-label=\"Suggestions\"`\n- Dropdown items use `role=\"option\"` with `aria-selected`\n- Disabled items have `aria-disabled`\n- The `clearable` clear button is a native button named \"Clear\": `Tab` from the input reaches it, and `Enter` or `Space` clears the input and puts focus back in it\n- Full keyboard navigation support",
"related": ["Input", "Select", "Taginput"],
"storybook": "https://bestax.io/storybook/?path=/story/form-autocomplete",
"summary": "The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.",
Expand All @@ -71,7 +71,7 @@
"name": "label",
"type": "React.ReactNode",
"default": null,
"description": "Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`).",
"description": "Field label, associated with the text input via `htmlFor`: through your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose label names the input instead when it points at it. The `Field` points its label there itself when the Autocomplete has no `id` and no inner `Field` sits between them (and the `Field` is not `grouped` or `hasAddons`); a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`. The label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\".",
"required": false,
"inherited": false,
"deprecated": false
Expand All @@ -80,7 +80,7 @@
"name": "labelProps",
"type": "React.LabelHTMLAttributes<HTMLLabelElement> & { [key: string]: unknown; }",
"default": null,
"description": "Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then).",
"description": "Props for the label element. An explicit `htmlFor` here overrides the automatic association (the input then gets no generated id). While the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise.",
"required": false,
"inherited": false,
"deprecated": false
Expand Down
8 changes: 4 additions & 4 deletions bestax-mcp/data/components/Field.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"code": "<Field horizontal>\n <Field.Label size=\"normal\">\n <label className=\"label\" htmlFor=\"compound-name\">\n Name\n </label>\n </Field.Label>\n <Field.Body>\n <Field.Control>\n <Input id=\"compound-name\" placeholder=\"Jane Doe\" />\n </Field.Control>\n </Field.Body>\n</Field>"
}
],
"accessibility": "- The `label` prop names the one control the Field holds. A composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase`, or `DateTimeInputBase`, or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id the label's `for` points at, so clicking the label focuses the control and assistive technology announces it. An `inline` picker renders no input, so it takes nothing.\n- A range `Slider` takes that id on its low thumb, and its thumbs also point `aria-labelledby` at the label (at `labelProps.id` when you set one), so under a label of \"Price range\" they announce as \"Price range Minimum value\" and \"Price range Maximum value\". An `ariaLabel` entry names its thumb instead, and an `aria-label` or `aria-labelledby` on the Slider takes the label's place in both names.\n- A group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`) can't take a `for`, so the label gets an id (yours from `labelProps.id`, otherwise a generated one) and the group points `aria-labelledby` at it. An `aria-label` or `aria-labelledby` you set on the group wins over the Field's label, as it does over a group's own `label`.\n- An `id` you set on the control wins too: it keeps that id, and the label then names it only if you point `labelProps={{ htmlFor }}` at it. Pass `labelProps={{ htmlFor: undefined }}` to opt out of the association entirely.\n- Association is skipped for `grouped`/`hasAddons` fields (they hold several controls), and a `Field` nested inside a labeled one starts its own scope. A horizontal Field wraps its children in a `Field.Body` of its own and keeps the association, but the pattern with an inner `Field` in that body needs it wired by hand.\n- Two controls in one plain labeled Field would both adopt its id. Give each an `id` of its own and label it individually.\n- A labeled Field whose content takes no `for`, a group included, renders its `for` unmatched. `Checkbox`, `Radio` and `Switch` take nothing from the label at all: each is named by its own children, so put the text there rather than in the Field's `label`. Where you point content at the label by hand, as with a group in an inner `Field`, pass `labelProps={{ id, htmlFor: undefined }}` so the label keeps its id and drops the `for`.\n- Grouped/horizontal layouts use Bulma’s grid for layout.\n- Always use the `label` prop or a custom label for clarity.",
"accessibility": "- The `label` prop names the one control the Field holds. A composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase`, or `DateTimeInputBase`, or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id the label's `for` points at, so clicking the label focuses the control and assistive technology announces it. An `inline` picker renders no input, so it takes nothing.\n- A range `Slider` takes that id on its low thumb, and its thumbs also point `aria-labelledby` at the label (at `labelProps.id` when you set one), so under a label of \"Price range\" they announce as \"Price range Minimum value\" and \"Price range Maximum value\". An `ariaLabel` entry names its thumb instead, and an `aria-label` or `aria-labelledby` on the Slider takes the label's place in both names. A label you wire by hand with `labelProps={{ htmlFor }}` gets no generated id, so it reaches the thumbs' names only when you give it an `id` there too, as in `labelProps={{ htmlFor: 'price', id: 'price-label' }}`.\n- An `Autocomplete` points its open suggestion list's `aria-labelledby` at the label the same way, so under a label of \"Country\" the list announces as \"Country\" rather than its fallback name, \"Suggestions\". A label you wire by hand needs an `id` in `labelProps` for this too, as in `labelProps={{ htmlFor: 'country', id: 'country-label' }}`.\n- A group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`) can't take a `for`, so the label gets an id (yours from `labelProps.id`, otherwise a generated one) and the group points `aria-labelledby` at it. An `aria-label` or `aria-labelledby` you set on the group wins over the Field's label, as it does over a group's own `label`.\n- An `id` you set on the control wins too: it keeps that id, and the label then names it only if you point `labelProps={{ htmlFor }}` at it. Pass `labelProps={{ htmlFor: undefined }}` to opt out of the association entirely.\n- Association is skipped for `grouped`/`hasAddons` fields (they hold several controls), and a `Field` nested inside a labeled one starts its own scope. A horizontal Field wraps its children in a `Field.Body` of its own and keeps the association, but the pattern with an inner `Field` in that body needs it wired by hand. A label you wire by hand names the control its `for` points at in a `grouped` or `hasAddons` field too, and with an `id` in `labelProps` it names a range `Slider`'s thumbs and an `Autocomplete`'s list there as well. No group points at it on its own.\n- Two controls in one plain labeled Field would both adopt its id. Give each an `id` of its own and label it individually.\n- A labeled Field whose content takes no `for`, a group included, renders its `for` unmatched. `Checkbox`, `Radio` and `Switch` take nothing from the label at all: each is named by its own children, so put the text there rather than in the Field's `label`. Where you point content at the label by hand, as with a group in an inner `Field`, pass `labelProps={{ id, htmlFor: undefined }}` so the label keeps its id and drops the `for`.\n- Grouped/horizontal layouts use Bulma’s grid for layout.\n- Always use the `label` prop or a custom label for clarity.",
"related": [
"Checkbox",
"Checkboxes",
Expand Down Expand Up @@ -149,7 +149,7 @@
"name": "label",
"type": "React.ReactNode",
"default": null,
"description": "Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children. Only the single inputs take the `htmlFor`, so with a group or any other content it matches nothing. Pass `labelProps={{ htmlFor }}` to wire your own `id`, or `labelProps={{ htmlFor: undefined }}` to opt out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own.",
"description": "Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children. Only the single inputs take the `htmlFor`, so with a group or any other content it matches nothing. Pass `labelProps={{ htmlFor }}` to wire your own `id`, or `labelProps={{ htmlFor: undefined }}` to opt out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own.",
"required": false,
"inherited": false,
"deprecated": false
Expand All @@ -167,7 +167,7 @@
"name": "labelProps",
"type": "React.LabelHTMLAttributes<HTMLLabelElement> & { [key: string]: unknown; }",
"default": null,
"description": "Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. An `id` here is the one a group control's, or a range `Slider`'s, `aria-labelledby` points at; otherwise the label gets a generated one while the association is on. To point a group in an inner `Field` at this label by hand, pass that `id` with `htmlFor: undefined`, or the label keeps a generated `htmlFor` that nothing takes.",
"description": "Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. While the association is on, the label renders with the `id` given here, or a generated one, and a group control, a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at it. A label you take over gets no generated id, and no group points at it on its own. With an `id` here, though, a range `Slider` or an `Autocomplete` whose `id` your `htmlFor` names still points its thumbs or its suggestion list at it, in a `grouped` or `hasAddons` Field too. To point a group in an inner `Field` at this label by hand, pass that `id` with `htmlFor: undefined`, or the label keeps a generated `htmlFor` that nothing takes.",
"required": false,
"inherited": false,
"deprecated": false
Expand Down Expand Up @@ -226,7 +226,7 @@
},
{
"path": "Field.Label",
"summary": "FieldLabel component for rendering a Bulma field label. It renders the label column of a horizontal `Field` (a `div` with the `field-label` class), not a `<label>`, so text placed straight in it names nothing. Put a `<label>` with the `label` class inside it and point its `htmlFor` at the control's `id`, or give the horizontal `Field` a `label` prop, which renders this column and its `<label>` for you.",
"summary": "FieldLabel component for rendering a Bulma field label. It renders the label column of a horizontal `Field` (a `div` with the `field-label` class), not a `<label>`, so text placed straight in it names nothing. Put a `<label>` with the `label` class inside it and point its `htmlFor` at the control's `id`, or give the horizontal `Field` a `label` prop, which renders this column and its `<label>` for you. A `<label>` you put here names the control through its `htmlFor` alone: a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at a `Field`'s label only when its `label` prop renders it and it names the control. Where it would not name the control on its own, as in an inner `Field`, pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.",
"component": null,
"props": [
{
Expand Down
Loading
Loading