# Web Forms 1.1.1: six issues (UI language fallback, title wrapping, guidance hints, region names, contrast, select\_one\_external)

**URL:** <https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660>\
**Category:** Support\
**Created:** [October 7, 2026, 11:48am UTC](https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660 "2026-10-07T11:48:06Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mercaint](https://getodk.b-cdn.net/user_avatar/forum.getodk.org/mercaint/32/33453_2.png) [@mercaint](https://forum.getodk.org/u/mercaint)\
**Post date:** [October 7, 2026, 11:48am UTC](https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660/1 "2026-10-07T11:48:06Z")

</div>

**1. What is the issue? Please be detailed.**

We use Central v2026.3.1 and embed `@getodk/web-forms` 1.1.1 (the version in central-frontend v2026.3.1) in an internal page where our team previews forms before publishing them. While testing that page with Chromium and axe-core 4.13 we found six issues. All of them reproduce with the unmodified npm build in a minimal host page, and the code involved in 1.1 to 1.5 looks unchanged on central-frontend `master` today. Two of them are related to open issues (getodk/web-forms#466 and #53).

**1.1 A regional browser language loses to any later exact match, so the UI language is often wrong**

With a form that declares no languages:

| `navigator.languages` | Submit button | Expected |
| --- | --- | --- |
| `['es']` or `['es-PA', 'es']` | Enviar | Enviar |
| `['es-PA']` or `['es-419']` | **Send** | Enviar |
| `['fr-CA']` | **Send** | Envoyer |
| `['en-US', 'es']` | **Enviar** | Send |
| `['es-PA', 'fr']` | **Envoyer** | Enviar |

Forms whose languages have no code (e.g. `label::Español`) behave the same; with a code (`label::Español (es)`) the UI follows the form language and is correct.

`findBestLocale()` tries exact matches for all candidates before it tries any base language, and `resolveUILocaleCandidates()` appends `en` to the browser languages. So for `['es-PA']` the candidates are `['es-PA', 'en']`, and `en` matches exactly before the base language `es` is tried (`packages/web-forms/src/lib/locale/useLocale.ts`). PrimeVue's locale is chosen with the same function and candidates. Trying each candidate's base language right after the candidate itself fixes every row above: we checked it by patching the 1.1.1 build.

**1.2 The form title breaks in the middle of words on narrow screens**

At 360 px wide, the title "Household survey on drinking water and sanitation" is shown as "Household survey on drin" / "king water and sanitation". The title `h1` has `word-break: break-all` (`FormHeader.vue`), added to fix long titles without spaces (getodk/web-forms#481). With `break-all`, any title that needs more than one line is cut at the last character that fits, usually in the middle of a word. With `word-break: normal; overflow-wrap: anywhere` instead, the title wraps at spaces, and a long title without spaces still wraps without horizontal scrolling (we checked both at 360 px).

**1.3 `guidance_hint` is appended to the hint and always shown**

A question with the hint "This is the hint." and the guidance\_hint "This is the guidance hint." shows a single hint: "This is the hint.This is the guidance hint." (with no space between them). A question with only a guidance\_hint shows it as a normal hint. The feature matrix doesn't mark guidance hints as supported (the row links to getodk/web-forms#53), so we expected them to be hidden, as Collect does by default. In `packages/xforms-engine/src/lib/reactivity/text/createTextRange.ts`, `generateChunksForTranslation()` adds every `<value>` of the itext entry as text unless its `form` is a media type, so `<value form="guidance">` ends up in the hint. Skipping `form="guidance"` values until #53 is done would match Collect's default.

**1.4 Group and repeat regions all have the same, empty name**

axe reports `landmark-unique` (moderate, a best-practice rule) on our form with two labelled groups and on our form with three repeat instances; from the code, it should happen whenever two or more group or repeat panels are shown. The content of each panel is a PrimeVue Panel region (`role="region"`) whose `aria-labelledby` points to the panel's toggle button. That button has no text and no `aria-label` (Web Forms uses its own clickable header and hides the button in `FormPanel.vue`), so every region's accessible name is empty. Passing the panel title to PrimeVue as `toggleButtonProps.ariaLabel` (or as the `header` prop) should be enough, e.g. "Household member 2" for a repeat instance.

**1.5 The Send button doesn't meet WCAG AA contrast (getodk/web-forms#466)**

White text on the primary color `#3e9fcc` is 2.98:1; AA needs 4.5:1, and axe reports `color-contrast` (serious). #466 proposes `#007DB8` (4.54:1); `odk-theme-preset.ts` on master still has `#3e9fcc`. At desktop widths (we saw it at 1024 and 1280 px, not at 360 or 800 px) axe also flags the "Powered by" and version text in the footer (`#64748b` on `#f1f5f9`, 4.34:1).

**1.6 `select_one_external` shows a free-text box**

The `<input query="...">` that pyxform generates for `select_one_external` is rendered as a plain text input, with no warning on screen or in the console, and it accepts any text. We know `select_one_external` isn't in the Web Forms feature matrix, but showing that the question isn't supported, instead of a text box, would avoid collecting free text by mistake.

**2. What steps can we take to reproduce this issue?**

1. In a blank page, install `webFormsPlugin` and mount `OdkWebForm` from `@getodk/web-forms@1.1.1` (npm) with Vue, passing `formXml`, `fetchFormAttachment` and an `onSubmit` handler, with no theme or locale overrides.
2. Convert the XLSForms below with pyxform 4.5.0 and open them in Chromium.
3. For 1.1, set the browser languages (for example, Playwright's `locale: 'es-PA'`), open form A and read the submit button.
4. For 1.2, open form A at 360 px wide.
5. For 1.3 and 1.6, open forms B and D (in D, type anything in District).
6. For 1.4 and 1.5, run axe-core 4.13 (WCAG 2.2 AA and best practices) on forms C, E and A at 1280 px wide.

Form A (1.1, 1.2, 1.5), with `form_title` "Household survey on drinking water and sanitation" in settings:

| type | name | label |
| --- | --- | --- |
| text | respondent | What is your name? |
| select\_one yes\_no | consent | Do you agree to take part? |

(choices: `yes_no` with yes/Yes and no/No)

Form B (1.3):

| type | name | label | hint | guidance\_hint |
| --- | --- | --- | --- | --- |
| text | q1 | Question with hint and guidance\_hint | This is the hint. | This is the guidance hint. |
| text | q2 | Question with guidance\_hint only | | Guidance only. |

Form C (1.4):

| type | name | label | repeat\_count |
| --- | --- | --- | --- |
| begin\_repeat | member | Household member | 3 |
| text | member\_name | Name | |
| end\_repeat | | | |

Form D (1.6), with `province` in choices and `district` (with a `province` column) in external\_choices:

| type | name | label | choice\_filter |
| --- | --- | --- | --- |
| select\_one province | province | Province | |
| select\_one\_external district | district | District | province=${province} |

Form E (1.4):

| type | name | label |
| --- | --- | --- |
| begin\_group | g1 | Section A |
| text | a | A |
| end\_group | | |
| begin\_group | g2 | Section B |
| text | b | B |
| end\_group | | |

**3. What have you tried to fix the issue?**

In our page we work around 1.1 by putting `es` first in `navigator.languages` before mounting, and 1.5 by setting `--p-primary-color`, `--p-primary-hover-color` and `--p-primary-active-color` to the 700, 800 and 900 shades, and `--odk-primary-text-color` to the 700 shade (about 5.4:1 for the button). For the other four we only warn our users. We're happy to test fixes or share the test page.

**4. Upload any forms or screenshots you can share publicly below.**

The forms are in the tables above. We can attach the XLSForm files and screenshots if that helps.

---

<div class="post-metadata">

**Author:** ![gareth](https://getodk.b-cdn.net/user_avatar/forum.getodk.org/gareth/32/30952_2.png) [@gareth](https://forum.getodk.org/u/gareth)\
**Post date:** [October 8, 2026, 1:18am UTC](https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660/2 "2026-10-08T01:18:08Z")

</div>

Hi @mercaint ! When you have a chance consider introducing yourself [here](https://forum.getodk.org/t/introduce-yourself-here/6671/1665) so we can learn more about how you're using ODK and Web Forms!

Thank you for your incredibly detailed investigation. I've managed to reproduce those problems and raised issues for them...

1.1: [New issue raised](https://github.com/getodk/web-forms/issues/937)

1.2: [New issue raised](https://github.com/getodk/web-forms/issues/938)

1.3: I think this is covered by [this comment](https://github.com/getodk/web-forms/issues/53#issuecomment-3947422054) . I'm not sure that hiding the guidance hint is correct, and maybe it's better to show it all the time, but with a line break, so it's separate from the hint. Or possibly we should just prioritise implementing guidance hints properly. I'll raise this for discussion.

1.4: [New issue raised](https://github.com/getodk/web-forms/issues/939)

1.5: I'll look at prioritising the issue you linked. Thanks.

1.6: I think this is the same as [this issue](https://github.com/getodk/web-forms/issues/928). You're right that Web Forms should not be showing this as a freetext input.

---

<div class="post-metadata">

**Author:** ![mercaint](https://getodk.b-cdn.net/user_avatar/forum.getodk.org/mercaint/32/33453_2.png) [@mercaint](https://forum.getodk.org/u/mercaint)\
**Post date:** [October 8, 2026, 10:44pm UTC](https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660/3 "2026-10-08T22:44:19Z")

</div>

Thanks a lot, Gareth, for reproducing all six so quickly, and for already fixing the title wrapping!

One note on 1.6: #928 is about Collect’s external-app fields (the ex: appearance and the intent attribute). select\_one\_external is a different case: pyxform writes it as an with a query attribute that refers to the external choices, with no intent or ex: appearance. So a fix that only looks at external apps might not catch it; it may be worth checking for query too.

Warm regards.

Oscar

---

<div class="post-metadata">

**Author:** ![gareth](https://getodk.b-cdn.net/user_avatar/forum.getodk.org/gareth/32/30952_2.png) [@gareth](https://forum.getodk.org/u/gareth)\
**Post date:** [October 8, 2026, 11:48pm UTC](https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660/4 "2026-10-08T23:48:40Z")

</div>

Ahh thanks for clarifying. You're right that's totally different. I'll figure out why it's missing and get back to you!

---

<div class="post-metadata">

**Author:** ![gareth](https://getodk.b-cdn.net/user_avatar/forum.getodk.org/gareth/32/30952_2.png) [@gareth](https://forum.getodk.org/u/gareth)\
**Post date:** [October 9, 2026, 12:16am UTC](https://forum.getodk.org/t/web-forms-1-1-1-six-issues-ui-language-fallback-title-wrapping-guidance-hints-region-names-contrast-select-one-external/58660/5 "2026-10-09T00:16:08Z")

</div>

I've raised a [new issue](https://github.com/getodk/web-forms/issues/941) to track 1.6.
