Skip to content

Commit

Permalink
Create a htmlIdGenerator utility hook
Browse files Browse the repository at this point in the history
- that creates a memoized ID, preventing the issue of re-randomized IDs on every component change
  • Loading branch information
cee-chen committed Sep 2, 2021
1 parent 96d3b50 commit c5bd90b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
* Side Public License, v 1.
*/

import { htmlIdGenerator } from './html_id_generator';
import React from 'react';
import { shallow } from 'enzyme';

import { htmlIdGenerator, useGeneratedHtmlId } from './html_id_generator';

jest.mock('./html_id_generator', () => {
return jest.requireActual('./html_id_generator');
Expand Down Expand Up @@ -51,3 +54,29 @@ describe('htmlIdGenerator', () => {
expect(generator()).not.toBe(generator());
});
});

describe('useGeneratedHtmlId', () => {
it('does not change when a component updates', () => {
const MockComponent: React.FC = (props) => (
<div id={useGeneratedHtmlId()} {...props} />
);
const component = shallow(<MockComponent />);
const initialId = component.find('div').prop('id');

component.setProps({ className: 'test' });
const rerenderedId = component.find('div').prop('id');

expect(initialId).toEqual(rerenderedId);
});

it('passes prefixes and suffixes to htmlIdGenerator', () => {
const MockComponent: React.FC = () => (
<div id={useGeneratedHtmlId({ prefix: 'hello', suffix: 'world' })} />
);
const component = shallow(<MockComponent />);
const id = component.find('div').prop('id');

expect(id!.startsWith('hello')).toBeTruthy();
expect(id!.endsWith('world')).toBeTruthy();
});
});
18 changes: 18 additions & 0 deletions src/services/accessibility/html_id_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import { v1 as uuidv1 } from 'uuid';
import { useMemo } from 'react';

/**
* This function returns a function to generate ids.
Expand All @@ -23,3 +24,20 @@ export function htmlIdGenerator(idPrefix: string = '') {
return `${prefix}${suffix ? staticUuid : uuidv1()}${suffix}`;
};
}

/**
* Generates an ID within a static ref object that remains static
* until the component using it is unmounted. This prevents IDs from
* being re-randomized on every component update.
*/
export const useGeneratedHtmlId = ({
prefix,
suffix,
}: {
prefix?: string;
suffix?: string;
} = {}) => {
return useMemo<string>(() => {
return htmlIdGenerator(prefix)(suffix);
}, [prefix, suffix]);
};
2 changes: 1 addition & 1 deletion src/services/accessibility/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
export { accessibleClickKeys } from './accessible_click_keys';
export { cascadingMenuKeys } from './cascading_menu_keys';
export { comboBoxKeys } from './combo_box_keys';
export { htmlIdGenerator } from './html_id_generator';
export { htmlIdGenerator, useGeneratedHtmlId } from './html_id_generator';
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export {
cascadingMenuKeys,
comboBoxKeys,
htmlIdGenerator,
useGeneratedHtmlId,
} from './accessibility';

export {
Expand Down

0 comments on commit c5bd90b

Please sign in to comment.