Skip to content

[@mantine/core] Input: Add keepErrorMounted prop for persistent error element (aria-live)#8953

Open
phamvutinh wants to merge 1 commit into
mantinedev:masterfrom
phamvutinh:feat/input-keep-error-mounted
Open

[@mantine/core] Input: Add keepErrorMounted prop for persistent error element (aria-live)#8953
phamvutinh wants to merge 1 commit into
mantinedev:masterfrom
phamvutinh:feat/input-keep-error-mounted

Conversation

@phamvutinh

Copy link
Copy Markdown

Closes #8932

Problem

Input.Wrapper (and therefore all inputs built on it — Select, TextInput, Textarea, etc.) unmounts the error element entirely when the error prop is falsy. This makes it impossible to use Mantine's built-in error node as a reliable aria-live region for field-level validation: each time an error appears a brand-new node is mounted instead of an existing one having its text updated, so screen reader announcements become inconsistent. Consumers currently have to render a second custom error element just to make validation accessible.

Solution

Add an opt-in keepErrorMounted prop (default false, fully backwards compatible). When set, the error element stays mounted even when there is no error, rendering empty content. Its text is then updated in place when an error appears/disappears, giving consumers a stable live-region host:

<TextInput
  label="Email"
  keepErrorMounted
  errorProps={{ 'aria-live': 'polite' }}
  error={hasError ? 'Required field' : null}
/>

Changes

  • Input.Wrapper: new keepErrorMounted prop on __InputWrapperProps; error node renders when hasError || keepErrorMounted, with empty content when there is no error. aria-describedby references the error id whenever the node is mounted.
  • use-input-props: route keepErrorMounted to the wrapper so all inputs (Select, TextInput, …) inherit it.
  • get-input-offsets: reserve the error slot spacing when keepErrorMounted so layout doesn't shift as the error toggles.
  • Docs: new "keepErrorMounted prop" section in input.mdx.
  • Tests added for InputWrapper and get-input-offsets.

Open question for maintainer

I went with an opt-in prop (no behavior change, no layout regression). aria-live is left to the consumer via errorProps rather than applied automatically — happy to adjust the approach (e.g. a documented pattern only, or auto aria-live) based on your preference.

Checks

npm run typecheck, npx oxlint, npm run build, and npm run jest for Input/Select all pass.

🤖 Generated with Claude Code

…t mounted for aria-live announcements

Closes mantinedev#8932

By default Input.Wrapper unmounts the error element when `error` is not set,
which prevents using it as a persistent aria-live region for validation
announcements. The new `keepErrorMounted` prop keeps the error node mounted
(rendering empty content when there is no error) so its text can be updated in
place. Available on all inputs that use Input.Wrapper (Select, TextInput, etc.).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Select unmounts error element, making aria-live validation announcements unreliable

1 participant