Skip to content

Fix/accessibility-issues-in-list-component #3618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 27, 2025

Conversation

Magnusrm
Copy link
Contributor

@Magnusrm Magnusrm commented Aug 18, 2025

Description

  • Resolves empty label complaint by accessibility tools, by providing a label instead of aria label and then hiding the label visually.
  • Also improves the readability of the labels used for radios and checkboxes.
  • Resolves complaint of empty header by adding a header value for screen readers and visually hiding it.
  • Fixes multiple labels specified for rowsPerPage selector when rendering several list components.

The issues mentioned in #1850 have been tested and are no longer an issue.

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

  • New Features

    • Improved accessibility in lists: screen-reader friendly row labels for selection controls and a visually hidden controls header.
    • Pagination now supports unique per-instance IDs so rows-per-page controls are uniquely labeled.
    • Instance Selection tables (mobile and desktop) now assign IDs to their pagination controls.
  • Documentation

    • Added translations for the controls header in English (“Row selectors”), Norwegian Bokmål (“Velg rad”), and Nynorsk (“Vel rad”).
  • Tests

    • Updated end-to-end selector to match the new per-instance rows-per-page control ID.

@Magnusrm Magnusrm added kind/bug Something isn't working backport-ignore This PR is a new feature and should not be cherry-picked onto release branches labels Aug 18, 2025
@Magnusrm Magnusrm self-assigned this Aug 18, 2025
@Magnusrm Magnusrm marked this pull request as ready for review August 18, 2025 11:27
Copy link

coderabbitai bot commented Aug 25, 2025

📝 Walkthrough

Walkthrough

Adds an id prop to Pagination and threads it through ListComponent and InstanceSelection to create per-instance DOM ids for the rows‑per‑page control; adds SR row labels and a visually hidden controls header in ListComponent; adds translations for list_component.controlsHeader; updates an E2E selector.

Changes

Cohort / File(s) Summary
Pagination prop and DOM ids
src/app-components/Pagination/Pagination.tsx
Adds public prop id: string to PaginationProps, destructures id in the component, and uses it to suffix the rows‑per‑page dropdown id and its label htmlFor (e.g. paginationRowsPerPageDropdown-${id}).
List component accessibility & id flow
src/layout/List/ListComponent.tsx
Adds getRowLabel helper to build screen‑reader row labels; switches Checkbox/Radio labeling to visually hidden labels; inserts a visually hidden controls header cell using list_component.controlsHeader; imports visuallyHidden classes and useLanguage; threads baseComponentId/id into Pagination usage in both mobile and desktop render paths.
Pagination usages with explicit ids
src/features/instantiate/selection/InstanceSelection.tsx
Adds id='instance-selection' to two Pagination instances (mobile and desktop tables).
Translations: controls header key
src/language/texts/en.ts, src/language/texts/nb.ts, src/language/texts/nn.ts
Adds list_component.controlsHeader translation key: English "Row selectors", Norwegian Bokmål "Velg rad", and Nynorsk "Vel rad". (Data-only additions.)
E2E selector update
test/e2e/pageobjects/datalist.ts
Updates public selector selectComponent from '#paginationRowsPerPageDropdown' to '#paginationRowsPerPageDropdown-listComponent' to match new instance‑scoped id.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1cf319b and 0e8c9e3.

📒 Files selected for processing (1)
  • src/language/texts/nn.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • src/language/texts/nn.ts
⏰ 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: Install
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/accessibility-issues-in-list-component

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 2

Caution

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

⚠️ Outside diff range comments (4)
src/app-components/Pagination/Pagination.tsx (2)

35-51: ARIA labels props are defined but not used (regression risk on mobile).

nextLabelAriaLabel and previousLabelAriaLabel exist in the type but are not destructured nor applied. When labels are hidden on mobile, prev/next buttons may lack accessible names.

Apply this diff to wire them up:

 export const Pagination = ({
-  id,
-  nextLabel,
-  previousLabel,
+  id,
+  nextLabel,
+  nextLabelAriaLabel,
+  previousLabel,
+  previousLabelAriaLabel,
   size,
   compact,
   hideLabels,
   currentPage,
   setCurrentPage,
   onChange,
   onPageSizeChange,
   numberOfRows = 0,
   rowsPerPageOptions,
   rowsPerPageText,
   showRowsPerPageDropdown = false,
   pageSize,
 }: PaginationProps) => {

104-107: Add explicit aria-labels to prev/next buttons.

Use the newly wired aria-label props so these buttons remain announced when text labels are hidden.

Apply this diff:

-            <DesignSystemPagination.Button {...prevButtonProps}>
+            <DesignSystemPagination.Button
+              aria-label={previousLabelAriaLabel || previousLabel}
+              {...prevButtonProps}
+            >
               {!hideLabels && !isMobile && previousLabel}
             </DesignSystemPagination.Button>
...
-            <DesignSystemPagination.Button {...nextButtonProps}>
+            <DesignSystemPagination.Button
+              aria-label={nextLabelAriaLabel || nextLabel}
+              {...nextButtonProps}
+            >
               {!hideLabels && !isMobile && nextLabel}
             </DesignSystemPagination.Button>

Also applies to: 122-125

src/features/instantiate/selection/InstanceSelection.tsx (1)

145-149: Missing ARIA labels on Prev/Next buttons

The nextLabelAriaLabel and previousLabelAriaLabel props are defined in PaginationProps but never actually forwarded into the usePagination hook (or onto the <DesignSystemPagination.Button>). As a result, when hideLabels is true or on mobile (where labels are hidden), the Prev/Next buttons have no aria-label, and screen readers will announce them only as “button” without context.

Please apply the following fixes in src/app-components/Pagination/Pagination.tsx ([around lines 17–25, 64, 104 & 122]):

• Include the ARIA-label props in the component’s destructuring.
• Pass them into usePagination({ … }) (or directly onto the Button as an explicit aria-label).

Suggested diff:

--- a/src/app-components/Pagination/Pagination.tsx
+++ b/src/app-components/Pagination/Pagination.tsx
@@ type PaginationProps = {
   nextLabel: string;
-  nextLabelAriaLabel: string;
+  nextLabelAriaLabel: string;
   previousLabel: string;
-  previousLabelAriaLabel: string;
+  previousLabelAriaLabel: string;
   size: NonNullable<Parameters<typeof DesignSystemPagination>[0]['data-size']>;
@@ export const Pagination = ({
-  id,
-  nextLabel,
-  previousLabel,
+  id,
+  nextLabel,
+  nextLabelAriaLabel,
+  previousLabel,
+  previousLabelAriaLabel,
   size,
   compact,
   hideLabels,
@@ const { pages, prevButtonProps, nextButtonProps } = usePagination({
-    currentPage,
-    setCurrentPage,
-    totalPages,
-    onChange,
-    showPages,
+    currentPage,
+    setCurrentPage,
+    totalPages,
+    onChange,
+    showPages,
+    nextLabelAriaLabel,
+    previousLabelAriaLabel,
 });

If the usePagination API doesn’t accept these keys, alternatively add aria-label directly:

<DesignSystemPagination.Button
  {...prevButtonProps}
  aria-label={previousLabelAriaLabel}
>
  {!hideLabels && !isMobile && previousLabel}
</DesignSystemPagination.Button>
src/layout/List/ListComponent.tsx (1)

279-287: Checkbox onChange is a no-op; keyboard/SR interaction won’t toggle selection. Also align visually-hidden class.

  • onChange={() => {}} prevents keyboard/AT users from changing state using the control itself.
  • Use the same utilClasses.visuallyHidden utility instead of 'sr-only' for consistency with the table header.

Apply this diff:

-                    label={<span className='sr-only'>{getRowLabel(row)}</span>}
-                    onChange={() => {}}
+                    label={<span className={utilClasses.visuallyHidden}>{getRowLabel(row)}</span>}
+                    onChange={() => toggle(row)}

Note: Keeping the row-level onClick handler is fine, but the control itself must toggle state via onChange for proper a11y.

🧹 Nitpick comments (5)
src/language/texts/en.ts (1)

381-381: Optional wording tweak for clarity/consistency.

Consider “Select row” (imperative) or “Row selection” (noun) to better mirror Bokmål “Velg rad” and typical column-header wording. Current “Row selectors” is understandable but slightly less idiomatic.

Apply one of these:

-    'list_component.controlsHeader': 'Row selectors',
+    'list_component.controlsHeader': 'Select row',

or

-    'list_component.controlsHeader': 'Row selectors',
+    'list_component.controlsHeader': 'Row selection',
src/app-components/Pagination/Pagination.tsx (1)

112-114: Minor ARIA nuance: Prefer aria-current="page" instead of boolean.

Spec-compliant value improves semantics for assistive tech.

Apply this diff:

-                  aria-current={currentPage === page}
+                  aria-current={currentPage === page ? 'page' : undefined}
src/features/instantiate/selection/InstanceSelection.tsx (1)

227-227: Tiny consistency nit: drop unnecessary unary plus.

onPageSizeChange already receives a number; the cast is redundant and diverges from the mobile path.

Apply this diff:

-                    onPageSizeChange={(value) => handleRowsPerPageChanged(+value)}
+                    onPageSizeChange={(value) => handleRowsPerPageChanged(value)}
src/layout/List/ListComponent.tsx (2)

211-211: Prefer indexedId for Pagination.id to guarantee uniqueness in repeating contexts

Using baseComponentId may collide if the List appears in repeating groups or multiple instances. indexedId is already computed and used for form control names; use it here too to ensure unique DOM IDs.

Apply this minimal change:

-          id={baseComponentId}
+          id={indexedId}

Please verify whether List can be rendered multiple times on a page (including within repeating groups). If yes, this change prevents duplicate IDs and label collisions.


318-318: Same uniqueness concern for desktop Pagination id

Mirror the mobile change: prefer indexedId over baseComponentId to avoid ID collisions if multiple Lists render on the same page.

Proposed change:

-          id={baseComponentId}
+          id={indexedId}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 15a54bf and 6859899.

📒 Files selected for processing (6)
  • src/app-components/Pagination/Pagination.tsx (4 hunks)
  • src/features/instantiate/selection/InstanceSelection.tsx (2 hunks)
  • src/language/texts/en.ts (1 hunks)
  • src/language/texts/nb.ts (1 hunks)
  • src/language/texts/nn.ts (1 hunks)
  • src/layout/List/ListComponent.tsx (10 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • src/language/texts/nn.ts
  • src/features/instantiate/selection/InstanceSelection.tsx
  • src/language/texts/nb.ts
  • src/language/texts/en.ts
  • src/app-components/Pagination/Pagination.tsx
  • src/layout/List/ListComponent.tsx
🧬 Code graph analysis (1)
src/layout/List/ListComponent.tsx (1)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
⏰ 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: Analyze (javascript)
  • GitHub Check: Install
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
🔇 Additional comments (11)
src/language/texts/nb.ts (1)

386-386: LGTM: New Bokmål key is correct and aligns with usage.

The translation “Velg rad” fits a hidden column header describing row selection controls.

src/app-components/Pagination/Pagination.tsx (2)

78-79: LGTM: Unique Select/Label association via per-instance id.

Good use of id/htmlFor to avoid duplicate labels when multiple paginations exist.

Also applies to: 93-94


15-20: Pagination id prop usage verified – all call sites updated

Only one import of the local Pagination component (src/app-components/Pagination/Pagination.tsx) is used in the repo, in src/features/instantiate/selection/InstanceSelection.tsx (line 143), and it already passes id='instance-selection'. No other call sites import the local Pagination, so no additional changes are required.

src/features/instantiate/selection/InstanceSelection.tsx (2)

144-158: LGTM: Stable per-instance id for Pagination (mobile).

Passing id='instance-selection' ensures unique rows-per-page label/input IDs in this view.


214-229: LGTM: Stable per-instance id for Pagination (desktop).

Matches the mobile path; only one view mounts at a time, so no duplicate IDs at runtime.

src/layout/List/ListComponent.tsx (6)

29-29: Import of utilClasses looks good

This will be used to apply visually-hidden styles in the table header. Consider using the same utility for the checkbox label later for consistency (see comment on Lines 279-287).


245-249: Visually hidden controls header: good accessibility improvement

Providing an explicit, visually hidden header for the selection column addresses “empty header” complaints from AT while keeping the UI clean.


291-293: RadioButton label/hideLabel pattern is correct; ensure getRowLabel is localized

Using hideLabel with a descriptive label is the right approach. Once getRowLabel is localized (see Lines 127-137), this will read correctly for screen readers.

Would you confirm that getRowLabel now returns localized text in your manual SR tests after applying the earlier change?


332-339: Requiring id on PaginationProps is reasonable

Making id mandatory clarifies intent and helps enforce unique control IDs for pagination UI pieces (e.g., rows-per-page). No issues spotted.


342-349: Destructuring id in Pagination is fine

No functional issues. This aligns with forwarding the identifier to the underlying pagination control.


360-374: CustomPagination id usage and translations verified

  • The id prop is consumed in Pagination.tsx to namespace the rows-per-page dropdown:
    • Select element has id={paginationRowsPerPageDropdown-${id}}
    • Corresponding <Label> uses htmlFor={paginationRowsPerPageDropdown-${id}}
  • ARIA label props are correctly forwarded:
    • previousLabelAriaLabel and nextLabelAriaLabel drive the button aria-label via prevButtonProps/nextButtonProps
  • All relevant translation keys are present in en.ts, nb.ts, and nn.ts:
    • list_component.controlsHeader
    • list_component.nextPage / nextPageAriaLabel
    • list_component.previousPage / previousPageAriaLabel
    • list_component.rowsPerPage

No further changes are needed.

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
src/layout/List/ListComponent.tsx (1)

286-297: Desktop checkbox is controlled but has a no-op onChange — keyboard users can’t toggle selection

With checked={isChecked(row)} and onChange={() => {}}, pressing Space on the checkbox won’t update selection. Relying on row onClick won’t help screen reader/keyboard activation. Also, prefer utilClasses.visuallyHidden over 'sr-only' for consistency.

Apply this diff to make the control operable and consistent:

-                  <Checkbox
-                    className={classes.toggleControl}
-                    label={<span className='sr-only'>{getRowLabel(row)}</span>}
-                    onChange={() => {}}
-                    value={JSON.stringify(row)}
-                    checked={isChecked(row)}
-                    name={indexedId}
-                  />
+                  <Checkbox
+                    className={classes.toggleControl}
+                    label={<span className={utilClasses.visuallyHidden}>{getRowLabel(row)}</span>}
+                    onChange={() => toggle(row)}
+                    onClick={(e) => e.stopPropagation()}
+                    value={JSON.stringify(row)}
+                    checked={isChecked(row)}
+                    name={indexedId}
+                  />

Additionally, to avoid double toggles when clicking inside the control cell, consider stopping propagation at the cell level:

// Outside selected lines, suggested for the Table.Cell that wraps the toggle
<Table.Cell
  onClick={(e) => e.stopPropagation()}
  className={cn({ [classes.selectedRowCell]: isRowSelected(row) })}
></Table.Cell>
♻️ Duplicate comments (1)
src/layout/List/ListComponent.tsx (1)

40-40: Good: localizing SR labels via useLanguage().

Introducing langAsString here enables translated, human-readable labels for assistive tech. This addresses the earlier request to localize row labels.

🧹 Nitpick comments (2)
src/layout/List/ListComponent.tsx (2)

29-29: Use a single visually-hidden utility consistently (prefer utilClasses.visuallyHidden over 'sr-only')

You already import utilClasses and use it for the header cell. Use the same class for the checkbox label to avoid relying on an undefined global 'sr-only' class.

Apply this diff:

-                    label={<span className='sr-only'>{getRowLabel(row)}</span>}
+                    label={<span className={utilClasses.visuallyHidden}>{getRowLabel(row)}</span>}

128-141: Make SR row labels deterministic and omit non-column fields; also localize booleans

Iterate headers in the same order as the table (keys of tableHeaders) so SR reads a predictable sequence and you don’t include fields that aren’t displayed. Optionally map booleans to localized Yes/No.

Confirm the translation keys you pick for Yes/No exist (example uses general.yes/general.no). If different keys are used in this repo, substitute accordingly.

-  const getRowLabel = (row: Row): string =>
-    Object.entries(row)
-      .map(([key]) => {
-        const headerId = tableHeaders[key];
-        if (!headerId) {
-          return '';
-        }
-        const header = langAsString(headerId);
-        const raw = row[key];
-        const value = typeof raw === 'string' ? langAsString(raw) : String(raw);
-        return `${header}: ${value}`;
-      })
-      .filter(Boolean)
-      .join(', ');
+  const getRowLabel = (row: Row): string =>
+    Object.keys(tableHeaders)
+      .map((key) => {
+        const headerId = tableHeaders[key];
+        if (!headerId) return '';
+        const header = langAsString(headerId);
+        const raw = row[key];
+        const value =
+          typeof raw === 'boolean'
+            ? langAsString(raw ? 'general.yes' : 'general.no')
+            : typeof raw === 'string'
+              ? langAsString(raw)
+              : String(raw);
+        return `${header}: ${value}`;
+      })
+      .filter(Boolean)
+      .join(', ');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6859899 and 923edf3.

📒 Files selected for processing (1)
  • src/layout/List/ListComponent.tsx (11 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • src/layout/List/ListComponent.tsx
🧬 Code graph analysis (1)
src/layout/List/ListComponent.tsx (2)
src/features/language/useLanguage.ts (1)
  • useLanguage (90-93)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
⏰ 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: Install
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
src/layout/List/ListComponent.tsx (6)

215-215: Propagating per-instance id to Pagination (mobile) is a solid fix

Passing id={baseComponentId} should eliminate duplicate ids when multiple lists are present.


322-322: Propagating per-instance id to Pagination (desktop) looks good

Aligns with the mobile path and prevents duplicate control labeling when multiple lists render.


336-336: PaginationProps now carries id — good addition

This makes id propagation explicit and type-safe across the boundary.


346-346: Accepting id in Pagination component signature — LGTM

Matches the updated props and enables downstream a11y/id fixes.


364-364: Forwarding id to CustomPagination — completes the fix

Ensures the underlying control can generate unique ids for rows-per-page and associated labels.


249-254: ✅ Translations Verified – Approving Changes

Translations for list_component.controlsHeader are present in all supported locales:

  • src/language/texts/en.ts : “Row selectors”
  • src/language/texts/nb.ts : “Velg rad”
  • src/language/texts/nn.ts : “Velg rad”

Great job adding the visually hidden header to satisfy accessibility requirements. Everything is in place—merging!

Copy link

@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: 0

🧹 Nitpick comments (2)
test/e2e/pageobjects/datalist.ts (2)

3-3: Make selector reusable by parameterizing the base component id

Hard-coding -listComponent makes this page object less reusable if another form uses a different instance id. Consider parameterizing the base id with a class field and interpolating it in the selector.

Apply this diff locally to improve reuse:

 export class Datalist {
   public listComponent = '#form-content-listComponent';
-  public selectComponent = '#paginationRowsPerPageDropdown-listComponent';
+  public readonly baseComponentId = 'listComponent';
+  public selectComponent = `#paginationRowsPerPageDropdown-${this.baseComponentId}`;
   public tableBody = '#form-content-listComponent table tbody';
   public navigateNextButton = '[data-testid=paginationNextButton]';
   public navigatePreviousButton = '[data-testid=paginationPreviousButton]';
   public radioButton = '[type=radio]';
   public searchInput = '#searchForList';
 }

3-3: Optional: prefer data-testid for stability over DOM ids

IDs tend to change with structural refactors; if feasible, exposing a data-testid="paginationRowsPerPageDropdown" on the Pagination control and selecting via [data-testid=paginationRowsPerPageDropdown] would reduce brittleness (similar to how next/prev buttons are targeted).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 923edf3 and 1cf319b.

📒 Files selected for processing (1)
  • test/e2e/pageobjects/datalist.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • test/e2e/pageobjects/datalist.ts
⏰ 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). (2)
  • GitHub Check: Install
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
🔇 Additional comments (2)
test/e2e/pageobjects/datalist.ts (2)

3-3: Selector update aligns with new per-instance Pagination IDs — LGTM

Matches the new paginationRowsPerPageDropdown-${id} scheme; using -listComponent here is consistent with the List component instance id.


3-3: No stale #paginationRowsPerPageDropdown selectors found

I ran the suggested searches across our E2E tests and confirmed:

  • rg -nP '#paginationRowsPerPageDropdown(?!-)' -g 'test/e2e/**' returned no matches, so there are no lingering references to the old ID without its -listComponent suffix.
  • Tests consistently use dataListPage.selectComponent (which points to #paginationRowsPerPageDropdown-listComponent), as seen in test/e2e/integration/frontend-test/list-component.ts.

No further updates are needed here.

Copy link

Copy link
Contributor

@olemartinorg olemartinorg left a comment

Choose a reason for hiding this comment

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

Looks good! 🙌 If #1850 should be closed when this is merged, you should probably link it as a related issue prefixed with "closing".

@Magnusrm Magnusrm merged commit a18a687 into main Aug 27, 2025
16 checks passed
@Magnusrm Magnusrm deleted the fix/accessibility-issues-in-list-component branch August 27, 2025 09:27
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

List component accessibility issues
2 participants