Skip to content

Commit d99419f

Browse files
feat: support getId (#724)
* feat: support getId * Update src/hooks/useId.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 7d3b130 commit d99419f

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

src/hooks/useId.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ export function resetUuid() {
1818
}
1919
}
2020

21+
/**
22+
* Generate a valid HTML id from prefix and key.
23+
* Sanitizes the key by replacing invalid characters with hyphens.
24+
* @param prefix - The prefix for the id
25+
* @param key - The key from React element, may contain spaces or invalid characters
26+
* @returns A valid HTML id string
27+
*/
28+
export function getId(prefix: string, key: string): string {
29+
// Valid id characters: letters, digits, hyphen, underscore, colon, period
30+
// Replace all invalid characters (including spaces) with hyphens to preserve length
31+
const sanitizedKey = key.replace(/[^a-zA-Z0-9_.:-]/g, '-');
32+
33+
return `${prefix}-${sanitizedKey}`;
34+
}
35+
2136
const useOriginId = getUseId();
2237

2338
export default useOriginId

tests/hooks.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { fireEvent, render } from '@testing-library/react';
22
import * as React from 'react';
33
import { renderToString } from 'react-dom/server';
44
import useId from '../src/hooks/useId';
5+
import { getId } from '../src/hooks/useId';
56
import useLayoutEffect from '../src/hooks/useLayoutEffect';
67
import useMemo from '../src/hooks/useMemo';
78
import useMergedState from '../src/hooks/useMergedState';
@@ -663,6 +664,18 @@ describe('hooks', () => {
663664
errorSpy.mockRestore();
664665
process.env.NODE_ENV = originEnv;
665666
});
667+
668+
it('should sanitize keys with invalid characters', () => {
669+
expect(getId('item', 'hello world')).toBe('item-hello-world');
670+
expect(getId('tab', 'user@name#123')).toBe('tab-user-name-123');
671+
expect(getId('panel', 'test/path\\file')).toBe('panel-test-path-file');
672+
expect(getId('menu', 'key with multiple spaces')).toBe(
673+
'menu-key-with--multiple---spaces',
674+
);
675+
expect(getId('btn', 'valid-key_123:456.789')).toBe(
676+
'btn-valid-key_123:456.789',
677+
);
678+
});
666679
});
667680

668681
describe('useMobile', () => {

0 commit comments

Comments
 (0)