Skip to content

Commit 9d8ee23

Browse files
fix(mosaic): forward refs from Select.Group and Select.GroupLabel
1 parent e86fe6b commit 9d8ee23

2 files changed

Lines changed: 34 additions & 16 deletions

File tree

‎packages/mosaic/src/primitives/select/__tests__/select.test.tsx‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { cleanup, render, screen, waitFor } from '@testing-library/react';
22
import userEvent from '@testing-library/user-event';
3+
import { createRef } from 'react';
34
import { afterEach, describe, expect, it, vi } from 'vitest';
45

56
import { axe } from '../../test-utils/axe';
@@ -993,6 +994,19 @@ describe('Select.Group', () => {
993994
expect(await axe(document.body, { rules: { region: { enabled: false } } })).toHaveNoViolations();
994995
});
995996

997+
it('forwards refs to the group and its label', () => {
998+
const groupRef = createRef<HTMLDivElement>();
999+
const labelRef = createRef<HTMLDivElement>();
1000+
render(
1001+
<Select.Group ref={groupRef}>
1002+
<Select.GroupLabel ref={labelRef}>Pome</Select.GroupLabel>
1003+
</Select.Group>,
1004+
);
1005+
1006+
expect(groupRef.current).toBe(screen.getByRole('group', { name: 'Pome' }));
1007+
expect(labelRef.current).toHaveTextContent('Pome');
1008+
});
1009+
9961010
it('throws when the label is used outside <Select.Group>', () => {
9971011
vi.spyOn(console, 'error').mockImplementation(() => {});
9981012
expect(() => render(<Select.GroupLabel>Fruits</Select.GroupLabel>)).toThrow(/within <Select.Group>/);
Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { createContext, useContext, useId } from 'react';
3+
import React, { createContext, useContext, useId } from 'react';
44

55
import { type ComponentProps, mergeProps, useRender } from '../utils';
66

@@ -9,7 +9,7 @@ const SelectGroupContext = createContext<string | undefined>(undefined);
99
export type SelectGroupProps = ComponentProps<'div'>;
1010

1111
/** A labelled set of options in the listbox, named by the `Select.GroupLabel` inside it. */
12-
export function SelectGroup(props: SelectGroupProps) {
12+
export const SelectGroup = React.forwardRef<HTMLDivElement, SelectGroupProps>(function SelectGroup(props, ref) {
1313
const { render, ...otherProps } = props;
1414
const labelId = useId();
1515

@@ -23,25 +23,29 @@ export function SelectGroup(props: SelectGroupProps) {
2323
{useRender({
2424
defaultTagName: 'div',
2525
render,
26+
ref,
2627
props: mergeProps<'div'>(defaultProps, otherProps),
2728
})}
2829
</SelectGroupContext.Provider>
2930
);
30-
}
31+
});
3132

3233
export type SelectGroupLabelProps = ComponentProps<'div'>;
3334

3435
/** Names the `Select.Group` it sits in. Throws outside one. */
35-
export function SelectGroupLabel(props: SelectGroupLabelProps) {
36-
const { render, ...otherProps } = props;
37-
const labelId = useContext(SelectGroupContext);
38-
if (labelId === undefined) {
39-
throw new Error('Select.GroupLabel must be used within <Select.Group>');
40-
}
41-
42-
return useRender({
43-
defaultTagName: 'div',
44-
render,
45-
props: mergeProps<'div'>({ id: labelId }, otherProps),
46-
});
47-
}
36+
export const SelectGroupLabel = React.forwardRef<HTMLDivElement, SelectGroupLabelProps>(
37+
function SelectGroupLabel(props, ref) {
38+
const { render, ...otherProps } = props;
39+
const labelId = useContext(SelectGroupContext);
40+
if (labelId === undefined) {
41+
throw new Error('Select.GroupLabel must be used within <Select.Group>');
42+
}
43+
44+
return useRender({
45+
defaultTagName: 'div',
46+
render,
47+
ref,
48+
props: mergeProps<'div'>({ id: labelId }, otherProps),
49+
});
50+
},
51+
);

0 commit comments

Comments
 (0)