From 590ae99ff77c5296258b322dd98351c7e2be20f5 Mon Sep 17 00:00:00 2001 From: eliasmurcray Date: Tue, 28 Oct 2025 10:21:47 -0700 Subject: [PATCH] fix(field): prevent NaN transforms when element is hidden Fixes #5815 When a field's display is set to none, getBoundingClientRect() returns zeros, causing division by zero in getLabelKeyframes(). This resulted in NaN values in transform strings. Added check to skip animation when label dimensions are zero. --- field/internal/field.ts | 4 ++++ field/internal/field_test.ts | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/field/internal/field.ts b/field/internal/field.ts index 4e747b3a13..58843333a1 100644 --- a/field/internal/field.ts +++ b/field/internal/field.ts @@ -320,6 +320,10 @@ export class Field extends LitElement { } = restingLabelEl.getBoundingClientRect(); const floatingScrollWidth = floatingLabelEl.scrollWidth; const restingScrollWidth = restingLabelEl.scrollWidth; + // If either label has no dimensions (e.g., display: none), skip animation + if (floatingScrollWidth === 0 || restingScrollWidth === 0) { + return []; + } // Scale by width ratio instead of font size since letter-spacing will scale // incorrectly. Using the width we can better approximate the adjusted // scale and compensate for tracking and overflow. diff --git a/field/internal/field_test.ts b/field/internal/field_test.ts index 8785e19551..93571f123d 100644 --- a/field/internal/field_test.ts +++ b/field/internal/field_test.ts @@ -408,4 +408,28 @@ describe('Field', () => { .toBeTrue(); }); }); + + describe('label animation', () => { + it('should not produce NaN transforms when populated while hidden', async () => { + const {instance} = await setupTest({label: 'Hidden Label'}); + instance.style.display = 'none'; + await env.waitForStability(); + const animateCalls: unknown[] = []; + spyOn(Element.prototype, 'animate').and.callFake((keyframes, options) => { + animateCalls.push(keyframes); + return new Animation(); + }); + const consoleErrorSpy = spyOn(console, 'error'); + instance.populated = true; + await env.waitForStability(); + for (const keyframe of animateCalls) { + const frames = Array.isArray(keyframe) ? keyframe : [keyframe]; + for (const frame of frames) { + const transform = (frame as any)?.transform ?? ''; + expect(transform).not.toMatch(/NaN/); + } + } + expect(consoleErrorSpy).not.toHaveBeenCalled(); + }); + }); });