From d4a7821e31ce9740bb6a77a752d5edf392adebb7 Mon Sep 17 00:00:00 2001 From: Robert T <20293876+tyreer@users.noreply.github.com> Date: Tue, 3 Feb 2026 22:09:01 -0800 Subject: [PATCH] fix(hiddenTextarea): use correct tabindex attribute to prevent keyboard focus --- src/calculateNodeHeight.tsx | 2 +- tests/index.spec.tsx | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/calculateNodeHeight.tsx b/src/calculateNodeHeight.tsx index 7e443a4..b869130 100644 --- a/src/calculateNodeHeight.tsx +++ b/src/calculateNodeHeight.tsx @@ -99,7 +99,7 @@ export default function calculateAutoSizeStyle( ): React.CSSProperties { if (!hiddenTextarea) { hiddenTextarea = document.createElement('textarea'); - hiddenTextarea.setAttribute('tab-index', '-1'); + hiddenTextarea.setAttribute('tabindex', '-1'); hiddenTextarea.setAttribute('aria-hidden', 'true'); // fix: A form field element should have an id or name attribute // A form field element has neither an id nor a name attribute. This might prevent the browser from correctly autofilling the form. diff --git a/tests/index.spec.tsx b/tests/index.spec.tsx index ff59503..cd74e3e 100644 --- a/tests/index.spec.tsx +++ b/tests/index.spec.tsx @@ -97,7 +97,7 @@ describe('TextArea', () => { }); it('should auto calculate height according to content length and autoSize property', async () => { - const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { }); const onInternalAutoSize = jest.fn(); const renderDemo = ( @@ -423,6 +423,36 @@ describe('TextArea', () => { }); }); +describe('Hidden Textarea Accessibility', () => { + it('should have tabindex="-1" to prevent keyboard focus', () => { + // Create a textarea to trigger hidden textarea creation + const wrapper = document.createElement('textarea'); + calculateAutoSizeStyle(wrapper); + + // Find the hidden textarea used for height measurement + const hiddenTextarea = document.querySelector( + 'textarea[name="hiddenTextarea"]', + ); + + expect(hiddenTextarea).toBeInTheDocument(); + // Verify correct tabindex attribute (without hyphen) + expect(hiddenTextarea).toHaveAttribute('tabindex', '-1'); + // Ensure the invalid "tab-index" attribute is NOT present + expect(hiddenTextarea).not.toHaveAttribute('tab-index'); + }); + + it('should have aria-hidden="true" for screen readers', () => { + const wrapper = document.createElement('textarea'); + calculateAutoSizeStyle(wrapper); + + const hiddenTextarea = document.querySelector( + 'textarea[name="hiddenTextarea"]', + ); + + expect(hiddenTextarea).toHaveAttribute('aria-hidden', 'true'); + }); +}); + describe('TextArea IME behavior', () => { it('should ignore Enter during composition', () => { const onPressEnter = jest.fn();