Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/quiet-trees-select.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
Comment thread
alexcarpenter marked this conversation as resolved.
1 change: 1 addition & 0 deletions packages/headless/src/primitives/select/select-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface SelectContextValue {
activeIndex: number | null;
setActiveIndex: React.Dispatch<React.SetStateAction<number | null>>;
selectedIndex: number | null;
setSelectedIndex: React.Dispatch<React.SetStateAction<number | null>>;
selectedValue: string | undefined;
selectedLabel: string | null;
elementsRef: React.MutableRefObject<Array<HTMLElement | null>>;
Expand Down
8 changes: 7 additions & 1 deletion packages/headless/src/primitives/select/select-option.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface SelectOptionProps extends ComponentProps<'button'> {

export function SelectOption(props: SelectOptionProps) {
const { render, value, label, disabled, ...otherProps } = props;
const { activeIndex, selectedValue, getItemProps, handleSelect, valueToLabelRef, selectedItemRef } =
const { activeIndex, selectedValue, setSelectedIndex, getItemProps, handleSelect, valueToLabelRef, selectedItemRef } =
useSelectContext();

const displayLabel = label ?? value;
Expand All @@ -31,6 +31,12 @@ export function SelectOption(props: SelectOptionProps) {
};
}, [value, displayLabel, valueToLabelRef]);

useEffect(() => {
if (isSelected) {
setSelectedIndex(index);
}
}, [index, isSelected, setSelectedIndex]);

const combinedRef = useMergeRefs([itemRef, isSelected ? selectedItemRef : null]);

const state = {
Expand Down
2 changes: 2 additions & 0 deletions packages/headless/src/primitives/select/select-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ function SelectInner(props: SelectProps) {
activeIndex,
setActiveIndex,
selectedIndex,
setSelectedIndex,
selectedValue,
selectedLabel,
elementsRef,
Expand All @@ -232,6 +233,7 @@ function SelectInner(props: SelectProps) {
activeIndex,
setActiveIndex,
selectedIndex,
setSelectedIndex,
selectedValue,
selectedLabel,
alignProp,
Expand Down
18 changes: 18 additions & 0 deletions packages/headless/src/primitives/select/select.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,24 @@ describe('Select', () => {
expect(activeOption).toBeInTheDocument();
});

it.each(['{ArrowDown}', '{ArrowUp}'])(
'opens from a focused trigger with %s and focuses the selected option',
async key => {
const user = userEvent.setup();
renderSelect({ defaultValue: 'banana' });

const trigger = screen.getByRole('combobox');
trigger.focus();

await user.keyboard(key);

const options = screen.getAllByRole('option');
expect(options[1]).toHaveAttribute('data-cl-selected', '');
expect(document.activeElement).toBe(options[1]);
expect(options[1]).toHaveAttribute('data-cl-active', '');
},
);

it('scrolls options into view on arrow key navigation', async () => {
const manyItems = Array.from({ length: 20 }, (_, i) => ({
label: `Item ${i + 1}`,
Expand Down
Loading