Skip to content

Conversation

@Magnusrm
Copy link
Contributor

@Magnusrm Magnusrm commented Dec 29, 2025

Description

This PR adds "role="alert" to the Alert component used for the soft validations in order to make the screen reader announce the contents when it renders.

I added an id to the validations and reference it in both input and textarea components "aria-describedby" because the debounced save when typing seemed to interrupt the validation message. Adding this seems to give the alert the priority.

I also moved som inline styling into css modules.

Related Issue(s)

Verification/QA

  • Manual functionality testing
    • I have tested these changes manually
    • Creator of the original issue (or service owner) has been contacted for manual testing (or will be contacted when released in alpha)
    • No testing done/necessary
  • Automated tests
    • Unit test(s) have been added/updated
    • Cypress E2E test(s) have been added/updated
    • No automatic tests are needed here (no functional changes/additions)
    • I want someone to help me make some tests
  • UU/WCAG (follow these guidelines until we have our own)
    • I have tested with a screen reader/keyboard navigation/automated wcag validator
    • No testing done/necessary (no DOM/visual changes)
    • I want someone to help me perform accessibility testing
  • User documentation @ altinn-studio-docs
    • Has been added/updated
    • No functionality has been changed/added, so no documentation is needed
    • I will do that later/have created an issue
  • Support in Altinn Studio
    • Issue(s) created for support in Studio
    • This change/feature does not require any changes to Altinn Studio
  • Sprint board
    • The original issue (or this PR itself) has been added to the Team Apps project and to the current sprint board
    • I don't have permissions to do that, please help me out
  • Labels
    • I have added a kind/* and backport* label to this PR for proper release notes grouping
    • I don't have permissions to add labels, please help me out

Summary by CodeRabbit

  • Accessibility Improvements

    • Enhanced form input and text area accessibility by improving how descriptions and validation messages are associated with controls, providing better support for assistive technologies and screen readers.
  • UI Changes

    • Restructured validation message display and introduced new styling options for soft validation messages to enhance the overall visual presentation and improve the user experience.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

Adds two CSS classes for soft validations, refactors validation rendering to use Alert components with container IDs/data attributes, and updates Input and TextArea components to include composite aria-describedby that references validation containers.

Changes

Cohort / File(s) Summary
CSS: Soft validation styles
src/features/validation/ComponentValidations.module.css
Adds .softValidation (margin-top, break-inside) and .softValidationListItem (padding-left, margin-bottom, list-style-type reset).
Validation rendering
src/features/validation/ComponentValidations.tsx
Replaces prior Alert wrapper with direct Alert usage for soft validations; renders a single Alert containing a list, removes an inner wrapper, and adds id and data-validation attributes plus aria-live on the outer container.
Form control accessibility
src/layout/Input/InputComponent.tsx, src/layout/TextArea/TextAreaComponent.tsx
Adds descriptionId and validationsId constants and composes aria-describedby (descriptionId + baseComponentId-validations) so inputs reference validation message containers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: fixing screen reader announcement of soft validation messages.
Description check ✅ Passed The description is complete, follows the template structure, includes related issue reference, and documents verification/QA activities with proper checkboxes marked.
Linked Issues check ✅ Passed The PR directly addresses issue #3064 by adding role='alert' to soft validation components and ensuring screen reader announcements via aria-describedby.
Out of Scope Changes check ✅ Passed All changes are within scope: adding Alert role, id/aria-describedby for accessibility, CSS module styling refinements, and refactoring validation rendering logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/aria-live-på-warnings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Magnusrm Magnusrm added backport-ignore This PR is a new feature and should not be cherry-picked onto release branches backport This PR should be cherry-picked onto older release branches kind/bug Something isn't working and removed backport-ignore This PR is a new feature and should not be cherry-picked onto release branches backport This PR should be cherry-picked onto older release branches labels Dec 29, 2025
@Magnusrm Magnusrm marked this pull request as ready for review January 7, 2026 08:37
@Magnusrm Magnusrm added the squad/utforming Issues that belongs to the named squad. label Jan 7, 2026
@Magnusrm Magnusrm moved this to 🔎 In review in Team Altinn Studio Jan 7, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/layout/TextArea/TextAreaComponent.tsx (1)

67-73: Major: Validations not linked when description is absent.

Same issue as InputComponent.tsx. The ariaDescribedBy is only set when both title and description exist, meaning validation messages won't be announced by screen readers when there's no description but validations are present.

The validations ID should be included in ariaDescribedBy even when there's no description, as long as there's a title.

🤖 Fix all issues with AI agents
In @src/features/validation/ComponentValidations.tsx:
- Around line 67-71: The parent div with id template using baseId currently has
aria-live='assertive' while child SoftValidations components render
role='alert', causing nested live regions and double announcements; pick one
strategy and make changes consistently: either remove aria-live='assertive' from
the parent container (the div using baseId and data-validation/indexedId) and
ensure SoftValidations (and any Alert-bearing children) keep role='alert' to own
announcements, or remove role='alert' from SoftValidations (and any child
Alerts) and rely on the parent's aria-live='assertive' so ErrorValidations and
SoftValidations use the same announcement mechanism. Ensure the chosen approach
is applied to both SoftValidations and ErrorValidations rendering paths so
live-region behavior is consistent.

In @src/layout/Input/InputComponent.tsx:
- Around line 136-139: The aria-describedby logic on InputComponent is excluding
validation IDs when description is missing, causing screen readers to miss
validation messages; update the aria-describedby computation (check
overrideDisplay?.renderedInTable, textResourceBindings?.title, and whether
validations exist) so that inputDescribedBy always includes the
`${baseComponentId}-validations` id when validations are present, and only
conditionally append the description id if a description exists (use the
existing inputDescribedBy and textResourceBindings checks to build the combined
describedBy string rather than requiring both title and description).
- Line 131: inputDescribedBy currently concatenates getDescriptionId(id) even
when it returns undefined, producing an invalid string like "undefined
component-validations"; change the construction of inputDescribedBy (the
variable computed using getDescriptionId, id and baseComponentId) to only
include the description id when getDescriptionId(id) returns a truthy value
(e.g., conditionally join parts or filter falsy values and join with a space) so
the resulting aria-describedby contains only real IDs such as "<descriptionId>
<baseComponentId>-validations" or just "<baseComponentId>-validations" when no
description exists.

In @src/layout/TextArea/TextAreaComponent.tsx:
- Line 44: The computed string textAreaDescribedBy in TextAreaComponent.tsx can
include the literal "undefined" when getDescriptionId(id) returns undefined;
change the assignment of textAreaDescribedBy to only include
getDescriptionId(id) when it is defined (e.g., build an array
[getDescriptionId(id), `${baseComponentId}-validations`], filter out falsy
entries, then join with a space) so the ARIA reference never contains the word
"undefined" and still includes `${baseComponentId}-validations`.
🧹 Nitpick comments (1)
src/features/validation/ComponentValidations.module.css (1)

13-17: Consider renaming for clarity.

The class name .softValidationListItem suggests it's for individual <li> elements, but it's actually applied to the <ul> container (line 135 in ComponentValidations.tsx). Consider renaming to .softValidationList for better semantic clarity.

📝 Suggested naming improvement
-.softValidationListItem {
+.softValidationList {
   padding-left: 0;
   margin-bottom: 0;
   list-style-type: none;
 }

Then update the usage in ComponentValidations.tsx line 135 accordingly.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57d7ac0 and 319c47f.

📒 Files selected for processing (4)
  • src/features/validation/ComponentValidations.module.css
  • src/features/validation/ComponentValidations.tsx
  • src/layout/Input/InputComponent.tsx
  • src/layout/TextArea/TextAreaComponent.tsx
🧰 Additional context used
📓 Path-based instructions (2)
{**/*.module.css,**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for component styling and leverage Digdir Design System components when possible

Files:

  • src/features/validation/ComponentValidations.module.css
  • src/features/validation/ComponentValidations.tsx
  • src/layout/TextArea/TextAreaComponent.tsx
  • src/layout/Input/InputComponent.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any type or type casting (as type) in TypeScript code; improve typing by avoiding casts and anys when refactoring
Use objects for managing query keys and functions, and queryOptions for sharing TanStack Query patterns across the system for central management

Files:

  • src/features/validation/ComponentValidations.tsx
  • src/layout/TextArea/TextAreaComponent.tsx
  • src/layout/Input/InputComponent.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-25T12:53:54.399Z
Learnt from: CR
Repo: Altinn/app-frontend-react PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:53:54.399Z
Learning: Applies to {**/*.module.css,**/*.{ts,tsx}} : Use CSS Modules for component styling and leverage Digdir Design System components when possible

Applied to files:

  • src/features/validation/ComponentValidations.module.css
🧬 Code graph analysis (3)
src/features/validation/ComponentValidations.tsx (2)
src/layout/Alert/index.tsx (1)
  • Alert (8-14)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
src/layout/TextArea/TextAreaComponent.tsx (1)
src/components/label/Label.tsx (1)
  • getDescriptionId (135-141)
src/layout/Input/InputComponent.tsx (2)
src/components/label/Label.tsx (1)
  • getDescriptionId (135-141)
src/app-components/Input/Input.tsx (1)
  • InputProps (15-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Install
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Install
🔇 Additional comments (3)
src/features/validation/ComponentValidations.module.css (1)

8-11: LGTM!

The .softValidation class provides appropriate spacing and prevents breaking the validation alert across pages/columns.

src/features/validation/ComponentValidations.tsx (2)

3-3: LGTM!

Correctly imports Alert from the Digdir Design System, aligning with the coding guidelines to leverage design system components.


72-90: LGTM!

The refactored structure with direct conditional rendering of validation groups is cleaner and more maintainable than the previous nested approach.

Comment on lines 67 to 71
<div
id={`${baseId}-validations`}
data-validation={indexedId}
aria-live='assertive'
style={{ display: 'contents' }}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file exists and its size
wc -l src/features/validation/ComponentValidations.tsx

Repository: Altinn/app-frontend-react

Length of output: 121


🏁 Script executed:

# Read the entire file to understand the context and verify the ARIA configuration
cat -n src/features/validation/ComponentValidations.tsx

Repository: Altinn/app-frontend-react

Length of output: 5945


🏁 Script executed:

# Check if there are any other uses of aria-live or role='alert' in similar patterns
rg "aria-live|role=['\"]alert['\"]" src/features/validation/ -A 2 -B 2

Repository: Altinn/app-frontend-react

Length of output: 883


Fix inconsistent ARIA live regions to prevent double announcements.

The parent container has aria-live='assertive' (line 70), while child SoftValidations components have role='alert' (line 133), which implicitly includes aria-live='assertive'. This creates nested live regions that may cause screen readers to announce validation messages twice.

Additionally, ErrorValidations relies on the parent's aria-live while SoftValidations has its own role='alert', creating an inconsistent announcement strategy across validation types.

Resolve by choosing one approach:

  1. Remove aria-live='assertive' from the parent and ensure all children that need announcements have role='alert', OR
  2. Remove role='alert' from individual child Alerts and rely solely on the parent's aria-live='assertive'
🤖 Prompt for AI Agents
In @src/features/validation/ComponentValidations.tsx around lines 67 - 71, The
parent div with id template using baseId currently has aria-live='assertive'
while child SoftValidations components render role='alert', causing nested live
regions and double announcements; pick one strategy and make changes
consistently: either remove aria-live='assertive' from the parent container (the
div using baseId and data-validation/indexedId) and ensure SoftValidations (and
any Alert-bearing children) keep role='alert' to own announcements, or remove
role='alert' from SoftValidations (and any child Alerts) and rely on the
parent's aria-live='assertive' so ErrorValidations and SoftValidations use the
same announcement mechanism. Ensure the chosen approach is applied to both
SoftValidations and ErrorValidations rendering paths so live-region behavior is
consistent.

Comment on lines +130 to +146
<Alert
className={classes.softValidation}
data-color={severity}
role='alert'
>
<ul className={classes.softValidationListItem}>
{validations.map((validation) => (
<li key={getUniqueKeyFromObject(validation)}>
<Lang
id={validation.message.key}
params={validation.message.params}
customTextParameters={validation.message.customTextParameters}
/>
</li>
))}
</ul>
</Alert>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

@digdir/designsystemet-react Alert component ARIA role attributes

💡 Result:

Short summary — ARIA for @digdir/designsystemet-react Alert

  • Static alerts (visible on page load): no special ARIA required; treat as normal content. [1][4]
  • Dynamic alerts (appear after page load):
    • Critical/urgent: use role="alert" on a live region wrapping the Alert (role="alert" ≈ aria-live="assertive"). [1][2][4]
    • Non‑critical/status messages: use role="status" or aria-live="polite" (recommend combining role="status" + aria-live="polite" for best compatibility). [1][2]
    • Don’t combine role="alert" with aria-live on the same element (may be announced twice in some screen readers). [1][2]
  • Implementation notes from Designsystemet:
    • Put the live-region attribute on an element that exists at page load and wrap the Alert — don’t rely on adding a populated alert element dynamically. [1]
    • For common cases the design system maps semantics: result/waiting → role="status" or aria-live="polite"; errors → role="alert" or aria-live="polite"/"assertive". [1]
  • References: Designsystemet Alert accessibility and System notifications pages; MDN ARIA alert role. [1][4][2]

🏁 Script executed:

# Search for Alert component imports in the codebase
rg "from.*designsystemet" --type ts --type tsx -A 2

# Check the specific file for context
head -160 src/features/validation/ComponentValidations.tsx | tail -40

Repository: Altinn/app-frontend-react

Length of output: 1102


🏁 Script executed:

# Find Alert component definition or import
rg "export.*Alert" --type ts --type tsx | head -20

# Search for Alert component file in designsystemet (may be node_modules or type definition)
find . -name "*.ts" -o -name "*.tsx" | xargs rg -l "interface Alert|type Alert" | head -5

# Check how severity is used with data-color attribute
rg "data-color.*severity|severity.*data-color" --type ts --type tsx -B 3 -A 3

Repository: Altinn/app-frontend-react

Length of output: 232


🏁 Script executed:

# Read the full ComponentValidations.tsx file to see imports
cat -n src/features/validation/ComponentValidations.tsx | head -50

# Search for Alert import from designsystemet
grep -n "import.*Alert" src/features/validation/ComponentValidations.tsx

# Check other Alert usages in the codebase with role attribute
rg "role=['\"]alert['\"]" -A 2 -B 2

Repository: Altinn/app-frontend-react

Length of output: 5711


🏁 Script executed:

# Check AlertSeverity definition
cat -n src/layout/Alert/config.generated.ts | grep -A 10 "AlertSeverity"

# Check if there are any other uses of 'warning'/'info'/'success' severity with role attributes
rg "severity.*warning|severity.*info|severity.*success" -B 3 -A 3

Repository: Altinn/app-frontend-react

Length of output: 8002


🏁 Script executed:

# Read AlertBaseComponent.tsx to see how it handles role and aria-live
cat -n src/layout/Alert/AlertBaseComponent.tsx

Repository: Altinn/app-frontend-react

Length of output: 1405


Remove explicit role='alert' or add proper aria-live with severity-aware handling.

The role='alert' on line 133 is semantically incorrect for non-critical alerts. According to ARIA best practices and the web search results, role="alert" should only be used for critical/urgent messages that require immediate screen reader announcement. Your component handles three severity levels:

  • 'warning': may warrant assertive announcement
  • 'info' and 'success': non-critical status messages that should use polite announcements

Currently, all three receive role='alert' (aria-live="assertive"), making info and success messages incorrectly assertive. Either:

  1. Remove the explicit role='alert' and add severity-aware aria-live (using the same logic as AlertBaseComponent.tsx: warning/danger → assertive, others → polite), or
  2. Use role='status' with aria-live='polite' for info/success, and role='alert' with aria-live='assertive' only for warnings.

Also note: the web search warns against combining role and aria-live on the same element in some screen readers. Use one or the other, or wrap the Alert in a separate live region container.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/layout/Input/InputComponent.tsx:
- Around line 138-141: The current aria-describedby logic prevents validation
announcements when descriptions are missing and the naive change risks pointing
to a non-existent element; update the logic in InputComponent (the
aria-describedby assignment using overrideDisplay?.renderedInTable,
textResourceBindings?.title/description, and inputDescribedBy) to only include
inputDescribedBy if the validation container will actually be rendered (i.e.,
there are validations for baseComponentId-validations as produced by
ComponentValidations) or alternatively always render the validation container
(ComponentValidations) in the DOM (even when empty) so inputDescribedBy is
always valid; choose one approach and implement the corresponding conditional
check/always-render change so aria-describedby never references a missing
element while still allowing validations to be announced when description is
absent.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 319c47f and 5c2268b.

📒 Files selected for processing (2)
  • src/layout/Input/InputComponent.tsx
  • src/layout/TextArea/TextAreaComponent.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/layout/TextArea/TextAreaComponent.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any type or type casting (as type) in TypeScript code; improve typing by avoiding casts and anys when refactoring
Use objects for managing query keys and functions, and queryOptions for sharing TanStack Query patterns across the system for central management

Files:

  • src/layout/Input/InputComponent.tsx
{**/*.module.css,**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for component styling and leverage Digdir Design System components when possible

Files:

  • src/layout/Input/InputComponent.tsx
🧬 Code graph analysis (1)
src/layout/Input/InputComponent.tsx (2)
src/components/label/Label.tsx (1)
  • getDescriptionId (135-141)
src/app-components/Input/Input.tsx (1)
  • InputProps (15-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
  • GitHub Check: Install
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
src/layout/Input/InputComponent.tsx (1)

7-7: LGTM! Clean ID construction for accessibility.

The import and ID construction logic correctly:

  • Derives descriptionId using the helper function
  • Creates a consistent validationsId pattern
  • Falls back gracefully when description is absent

Also applies to: 131-133

Comment on lines 138 to 141
'aria-describedby':
overrideDisplay?.renderedInTable !== true && textResourceBindings?.title && textResourceBindings?.description
? getDescriptionId(id)
? inputDescribedBy
: undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n src/layout/Input/InputComponent.tsx | sed -n '130,150p'

Repository: Altinn/app-frontend-react

Length of output: 1228


🏁 Script executed:

# Search for validation container ID pattern
rg -n 'validations' src/layout/Input/InputComponent.tsx | head -20

Repository: Altinn/app-frontend-react

Length of output: 230


🏁 Script executed:

rg -n 'ComponentValidations' src/layout/Input/InputComponent.tsx -A 3 -B 3

Repository: Altinn/app-frontend-react

Length of output: 51


🏁 Script executed:

cat -n src/layout/Input/InputComponent.tsx | sed -n '125,145p'

Repository: Altinn/app-frontend-react

Length of output: 1326


🏁 Script executed:

# Search for where validation content is rendered in Input directory
rg -n 'validations' src/layout/Input/ -A 2 -B 2 | head -50

Repository: Altinn/app-frontend-react

Length of output: 1795


🏁 Script executed:

fd -e tsx -e ts src/layout/Input/ | xargs rg -l 'return.*(' | head -5

Repository: Altinn/app-frontend-react

Length of output: 511


🏁 Script executed:

rg -n '<div.*validationsId|id=.*validationsId' src/layout/Input/ -A 2 -B 2

Repository: Altinn/app-frontend-react

Length of output: 51


🏁 Script executed:

# Get the entire InputComponent.tsx file or at least the render section
wc -l src/layout/Input/InputComponent.tsx

Repository: Altinn/app-frontend-react

Length of output: 108


🏁 Script executed:

cat src/layout/Input/InputComponent.tsx | grep -n "return\|ComponentValidations\|validationsId" | head -30

Repository: Altinn/app-frontend-react

Length of output: 1065


🏁 Script executed:

rg -n 'id.*validationsId|validationsId.*=' src/layout/Input/InputComponent.tsx -B 2 -A 2

Repository: Altinn/app-frontend-react

Length of output: 376


🏁 Script executed:

# Get line count first
wc -l src/layout/Input/InputComponent.tsx

Repository: Altinn/app-frontend-react

Length of output: 108


🏁 Script executed:

# View the return statement from line 253 onwards
cat -n src/layout/Input/InputComponent.tsx | sed -n '253,272p'

Repository: Altinn/app-frontend-react

Length of output: 759


🏁 Script executed:

rg -n 'ComponentValidations' src/layout/Input/ -A 5

Repository: Altinn/app-frontend-react

Length of output: 51


🏁 Script executed:

rg -n 'validationsId' src/layout/ -B 3 -A 3 | head -50

Repository: Altinn/app-frontend-react

Length of output: 1399


🏁 Script executed:

# Search for ComponentStructureWrapper to understand how validations are rendered
rg -n 'ComponentStructureWrapper' src/layout/ --type tsx --type ts -A 10 | head -50

Repository: Altinn/app-frontend-react

Length of output: 96


🏁 Script executed:

rg -n 'id=.*validationsId' src/layout/ -B 3 -A 3 | head -50

Repository: Altinn/app-frontend-react

Length of output: 51


🏁 Script executed:

rg -n 'export.*ComponentStructureWrapper|function ComponentStructureWrapper' src/ --type tsx --type ts -A 15 | head -80

Repository: Altinn/app-frontend-react

Length of output: 96


🏁 Script executed:

# Search for ComponentStructureWrapper definition
rg -n 'ComponentStructureWrapper' src/layout/ -A 10 | head -50

Repository: Altinn/app-frontend-react

Length of output: 3842


🏁 Script executed:

# Search for where validations div is rendered
rg -n 'id.*=.*validationsId' src/ -B 2 -A 2 | head -50

Repository: Altinn/app-frontend-react

Length of output: 51


🏁 Script executed:

# Find the ComponentStructureWrapper file
fd 'ComponentStructureWrapper' src/

Repository: Altinn/app-frontend-react

Length of output: 109


🏁 Script executed:

# View the ComponentStructureWrapper file
cat -n src/layout/ComponentStructureWrapper.tsx

Repository: Altinn/app-frontend-react

Length of output: 2089


🏁 Script executed:

# Find and view AllComponentValidations
rg -n 'export.*AllComponentValidations|function AllComponentValidations' src/ -A 20 | head -60

Repository: Altinn/app-frontend-react

Length of output: 2020


🏁 Script executed:

# Search for the validationsId div pattern
fd 'ComponentValidations' src/ -type f

Repository: Altinn/app-frontend-react

Length of output: 239


🏁 Script executed:

# Find ComponentValidations file
find src -name '*ComponentValidations*'

Repository: Altinn/app-frontend-react

Length of output: 173


🏁 Script executed:

# View the full ComponentValidations.tsx file
cat -n src/features/validation/ComponentValidations.tsx | head -100

Repository: Altinn/app-frontend-react

Length of output: 4395


🏁 Script executed:

# Confirm the validation container behavior - check if it can be rendered empty
cat -n src/features/validation/ComponentValidations.tsx | sed -n '36,70p'

Repository: Altinn/app-frontend-react

Length of output: 1775


Critical accessibility issue: Validations not announced when description is missing, but proposed fix would create invalid aria-describedby references.

The condition requiring both textResourceBindings?.title and textResourceBindings?.description to set aria-describedby prevents validations from being announced via screen readers when a description is absent. However, the validation container (with ID ${baseComponentId}-validations) is only rendered when validations exist (ComponentValidations.tsx, lines 62-64 returns null if no validations).

The proposed fix of unconditionally using aria-describedby: overrideDisplay?.renderedInTable !== true ? inputDescribedBy : undefined would reference a non-existent DOM element when no validations are present, creating broken aria-describedby attributes.

A proper fix requires checking whether validations will be rendered before setting aria-describedby, or restructuring the validation container to always render in the DOM (even if empty) to make the simplified condition safe.

🤖 Prompt for AI Agents
In @src/layout/Input/InputComponent.tsx around lines 138 - 141, The current
aria-describedby logic prevents validation announcements when descriptions are
missing and the naive change risks pointing to a non-existent element; update
the logic in InputComponent (the aria-describedby assignment using
overrideDisplay?.renderedInTable, textResourceBindings?.title/description, and
inputDescribedBy) to only include inputDescribedBy if the validation container
will actually be rendered (i.e., there are validations for
baseComponentId-validations as produced by ComponentValidations) or
alternatively always render the validation container (ComponentValidations) in
the DOM (even when empty) so inputDescribedBy is always valid; choose one
approach and implement the corresponding conditional check/always-render change
so aria-describedby never references a missing element while still allowing
validations to be announced when description is absent.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 8, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-ignore This PR is a new feature and should not be cherry-picked onto release branches kind/bug Something isn't working squad/utforming Issues that belongs to the named squad.

Projects

Status: 🔎 In review

Development

Successfully merging this pull request may close these issues.

Myke kontroller (warning) leses ikke automatisk av skjermleser for en rekke metoder

1 participant