Skip to content

fix datepicker with 400% zoom and mobileview#4143

Open
walldenfilippa wants to merge 4 commits intomainfrom
fix/4002-datepicker-modal-zoom
Open

fix datepicker with 400% zoom and mobileview#4143
walldenfilippa wants to merge 4 commits intomainfrom
fix/4002-datepicker-modal-zoom

Conversation

@walldenfilippa
Copy link
Copy Markdown
Contributor

@walldenfilippa walldenfilippa commented Apr 27, 2026

Description

Designsystemet’s datepicker component does not currently handle larger layouts very well. As a result, I have had to make some adjustments to the layout in the caption section in order to support mobile screens and zooming.

Datepicker with 400% zoom and browser size is 1280px:

datepicker.mp4

Mobile view:
image

Related Issue(s)

  • closes #{issue number}

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

    • Mobile datepicker now includes a visible close button inside the modal for easier dismissal.
  • Style

    • Improved modal presentation with a dedicated container and scrollable content.
    • Enhanced mobile responsiveness: datepicker displays full-width on small screens (≤480px) with adjusted calendar sizing and tighter caption/dropdown layout.
    • Caption and dropdown layout updated for clearer alignment and accessibility.
  • Tests

    • Added/updated tests to verify mobile close behavior and dialog removal from the DOM.

@walldenfilippa walldenfilippa added kind/bug Something isn't working backport This PR should be cherry-picked onto older release branches squad/utforming Issues that belongs to the named squad. labels Apr 27, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 83f1ae00-fadb-44c5-a52d-eba03883c812

📥 Commits

Reviewing files that changed from the base of the PR and between 4652468 and a660721.

📒 Files selected for processing (2)
  • src/app-components/Datepicker/DatepickerDialog.tsx
  • src/layout/Datepicker/DatepickerComponent.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/layout/Datepicker/DatepickerComponent.test.tsx
  • src/app-components/Datepicker/DatepickerDialog.tsx

📝 Walkthrough

Walkthrough

Adds modal-specific CSS and responsive rules for the datepicker, introduces a DatePickerCloseContext and exported useDatePickerClose() hook, updates caption/dropdown layout and conditional close-button rendering, and expands tests to verify mobile dialog close behavior and desktop conditional rendering.

Changes

Cohort / File(s) Summary
Datepicker Styling
src/app-components/Datepicker/Calendar.module.css
Adds .datepickerModal, .datepickerModalContent, .datepickerDropdowns; renames .dropdownCaption.datepickerCaption; adds max-height/scrolling and responsive (@media (max-width:480px)) layout rules for full-width calendar/table and grid caption/dropdown/close-button arrangement.
Dialog Context & Modal Integration
src/app-components/Datepicker/DatepickerDialog.tsx
Adds DatePickerCloseContext and exports useDatePickerClose(); provides a shared closeDatepicker handler to mobile Dialog (disables Dialog closeButton), moves mobile sizing to CSS modules and wires onClose to the shared handler; reuses handler for non-mobile Popover.onClose.
Caption Component & Close Button
src/layout/Datepicker/DropdownCaption.tsx
Switches to styles.datepickerCaption and styles.datepickerDropdowns; consumes useDatePickerClose() and conditionally renders a tertiary close button (XMarkIcon) that calls the provided close handler with localized aria-label.
Tests (mobile & desktop flows)
src/layout/Datepicker/DatepickerComponent.test.tsx
Introduces mockHTMLDialogElement() helper and restores prototype afterEach; updates mobile dialog test to use helper; adds tests verifying mobile dialog can be closed via the “Lukk” button and is removed from DOM, and that desktop flow does not render the mobile close button.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 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 summarizes the primary changes: fixing datepicker behavior for both 400% zoom and mobile view layouts.
Description check ✅ Passed The description includes the required sections: a clear summary of changes with visual references, related issues (placeholder), and comprehensive QA/verification checklist responses.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/4002-datepicker-modal-zoom

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
src/app-components/Datepicker/DatepickerDialog.tsx (1)

62-67: Add a focused regression test for the custom close path.

Since the built-in dialog close button is disabled at Line 62, I’d recommend an interaction test asserting the custom close button remains present and closes the dialog in mobile mode.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app-components/Datepicker/DatepickerDialog.tsx` around lines 62 - 67,
DatepickerDialog disables the built-in close button (closeButton={false}), so
add a focused regression test that renders the DatepickerDialog in mobile mode,
locates the custom close button exposed in the component (e.g., the element
inside styles.datepickerModalContent or the custom close button
text/aria-label), simulates a user click (userEvent.click) and asserts the
dialog closes by either verifying the onClose/setIsDialogOpen handler was called
or the dialog is removed from the DOM; ensure the test sets up mobile sizing
(window.innerWidth or the same mobile condition your component uses) and uses
RTL queries to avoid implementation coupling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/app-components/Datepicker/DatepickerDialog.tsx`:
- Around line 62-67: DatepickerDialog disables the built-in close button
(closeButton={false}), so add a focused regression test that renders the
DatepickerDialog in mobile mode, locates the custom close button exposed in the
component (e.g., the element inside styles.datepickerModalContent or the custom
close button text/aria-label), simulates a user click (userEvent.click) and
asserts the dialog closes by either verifying the onClose/setIsDialogOpen
handler was called or the dialog is removed from the DOM; ensure the test sets
up mobile sizing (window.innerWidth or the same mobile condition your component
uses) and uses RTL queries to avoid implementation coupling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 903c975d-b7db-40c3-b4db-12527ad55ba0

📥 Commits

Reviewing files that changed from the base of the PR and between 51af1b3 and 1b1d2e0.

📒 Files selected for processing (3)
  • src/app-components/Datepicker/Calendar.module.css
  • src/app-components/Datepicker/DatepickerDialog.tsx
  • src/layout/Datepicker/DropdownCaption.tsx

@walldenfilippa walldenfilippa linked an issue Apr 28, 2026 that may be closed by this pull request
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
src/layout/Datepicker/DatepickerComponent.test.tsx (1)

223-233: Centralize dialog prototype mocks to prevent cross-test leakage.

This test duplicates global HTMLDialogElement.prototype mutations already present at line 72–82. These mocks persist across tests with no cleanup, causing potential isolation issues. Extract to a helper and restore in afterEach.

♻️ Suggested refactor
+const mockDialogElementMethods = () => {
+  const originalShow = HTMLDialogElement.prototype.show;
+  const originalShowModal = HTMLDialogElement.prototype.showModal;
+  const originalClose = HTMLDialogElement.prototype.close;
+
+  HTMLDialogElement.prototype.show = function mock(this: HTMLDialogElement) {
+    this.open = true;
+  };
+  HTMLDialogElement.prototype.showModal = function mock(this: HTMLDialogElement) {
+    this.open = true;
+  };
+  HTMLDialogElement.prototype.close = function mock(this: HTMLDialogElement) {
+    this.open = false;
+  };
+
+  return () => {
+    HTMLDialogElement.prototype.show = originalShow;
+    HTMLDialogElement.prototype.showModal = originalShowModal;
+    HTMLDialogElement.prototype.close = originalClose;
+  };
+};
+
 describe('DatepickerComponent', () => {
+  let restoreDialogMethods: (() => void) | undefined;
   beforeEach(() => {
     setScreenWidth(1366);
+    restoreDialogMethods = undefined;
   });
+
+  afterEach(() => {
+    restoreDialogMethods?.();
+  });
 
   it('should show close button in mobile screen and close modal when clicked', async () => {
-    //Workaround since there is no support for dialog element functions yet in jest.
-    HTMLDialogElement.prototype.show = jest.fn(function mock(this: HTMLDialogElement) {
-      this.open = true;
-    });
-    HTMLDialogElement.prototype.showModal = jest.fn(function mock(this: HTMLDialogElement) {
-      this.open = true;
-    });
-    HTMLDialogElement.prototype.close = jest.fn(function mock(this: HTMLDialogElement) {
-      this.open = false;
-    });
+    restoreDialogMethods = mockDialogElementMethods();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/layout/Datepicker/DatepickerComponent.test.tsx` around lines 223 - 233,
Duplicate mutations to HTMLDialogElement.prototype (show, showModal, close) in
DatepickerComponent.test.tsx cause cross-test leakage; extract the three
prototype mocks into a shared helper (e.g., createDialogMocks or
setupDialogMocks) and call it from tests or global test setup, then in an
afterEach restore the original methods (keep references to originals before
mocking) to ensure isolation and remove the duplicate mock block at lines where
show/showModal/close are currently redefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/layout/Datepicker/DatepickerComponent.test.tsx`:
- Around line 223-233: Duplicate mutations to HTMLDialogElement.prototype (show,
showModal, close) in DatepickerComponent.test.tsx cause cross-test leakage;
extract the three prototype mocks into a shared helper (e.g., createDialogMocks
or setupDialogMocks) and call it from tests or global test setup, then in an
afterEach restore the original methods (keep references to originals before
mocking) to ensure isolation and remove the duplicate mock block at lines where
show/showModal/close are currently redefined.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7b021d4-32a8-486f-9211-3cb703dd4e36

📥 Commits

Reviewing files that changed from the base of the PR and between 1b1d2e0 and 4652468.

📒 Files selected for processing (1)
  • src/layout/Datepicker/DatepickerComponent.test.tsx

>
{children}
</Dialog>
<DatePickerCloseContext.Provider value={() => setIsDialogOpen(false)}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe as sonarCloud suggest , we can add callback something like ;

const closeDatePicker = useCallback(() => setIsDialogOpen(false), [setIsDialogOpen]);

and then use it in:
DatePickerCloseContext.Provider value={closeDatePicker}
Mobile Dialog onClose={closeDatePicker}
Desktop Popover onClose={closeDatePicker}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Extracting it as a named const to avoid repeating the same inline function in three places is a good idea. I will skipp useCallback since setIsDialogOpen never changes between renders.

Copy link
Copy Markdown
Contributor

@JamalAlabdullah JamalAlabdullah left a comment

Choose a reason for hiding this comment

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

Works fine 👍

@sonarqubecloud
Copy link
Copy Markdown

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

Labels

backport This PR should be cherry-picked onto older release branches kind/bug Something isn't working squad/utforming Issues that belongs to the named squad.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Datepicker on 400% zoom makes some buttons inaccessible

2 participants