Skip to content
Merged
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: 1 addition & 1 deletion packages/@react-spectrum/s2/src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ export const Picker = /*#__PURE__*/ (forwardRef as forwardRefType)(function Pick
aria-describedby={spinnerId}
placeholder={placeholder}
style={UNSAFE_style}
className={UNSAFE_className + style(field(), getAllowedOverrides())({
className={UNSAFE_className + style({...field(), position: 'relative'}, getAllowedOverrides())({
isInForm: !!formContext,
labelPosition,
size
Expand Down
25 changes: 25 additions & 0 deletions packages/react-aria-components/docs/Select.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import {Select, SelectValue, Label, Button, Popover, ListBox, ListBoxItem} from

.react-aria-Select {
color: var(--text-color);
position: relative;
max-width: 250px;
width: fit-content;

Expand Down Expand Up @@ -1273,3 +1274,27 @@ it('Select can select an option via keyboard', async function () {
```

<ClassAPI links={selectUtil.links} class={selectUtil.exports.SelectTester} />

## Gotchas

`Select` requires a `position: relative` either on itself or on a close parent. This is because
the `Popover` component uses a hidden input to manage native form functionality. The hidden input
is absolutely positioned and can spill out unexpectedly if the parent is not positioned relative
causing unintended scroll bars to appear.

Note: you do not need to set the style inline, you can use any CSS method to do it.

```tsx render=false
<Select style={{position: 'relative'}}>
<Label>Favorite Animal</Label>
<Button>
<SelectValue />
<span aria-hidden="true">▼</span>
</Button>
<Popover>
<ListBox>
...
</ListBox>
</Popover>
</Select>
```
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function SelectExample() {

return (
<div className="bg-linear-to-br from-cyan-200 to-blue-400 p-8 sm:h-[350px] rounded-lg flex justify-center">
<Select className="flex flex-col gap-1 w-[200px]">
<Select className="flex flex-col gap-1 w-[200px] relative">
<Label className="text-black cursor-default">Language</Label>
<Button className="flex items-center cursor-default rounded-lg border-0 bg-white/90 pressed:bg-white transition py-2 pl-5 pr-2 text-base text-left leading-normal ring-1 ring-black/5 shadow-md text-gray-700 focus:outline-hidden focus-visible:outline-2 outline-black outline-offset-3 focus-visible:ring-black/25">
<SelectValue className="flex-1 truncate" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import CheckIcon from '@spectrum-icons/workflow/Checkmark';
function SelectExample() {
return (
<div className="bg-linear-to-tl from-amber-500 to-rose-700 p-8 sm:h-[250px] rounded-lg flex justify-center">
<Select className="flex flex-col gap-1 w-[200px]">
<Select className="flex flex-col gap-1 w-[200px] relative">
<Label className="text-white cursor-default">Status</Label>
<Button className="flex items-center cursor-default rounded-lg border-0 bg-white/90 pressed:bg-white transition py-2 pl-5 pr-2 text-base text-left leading-normal shadow-md text-gray-700 focus:outline-hidden focus-visible:ring-2 ring-white ring-offset-2 ring-offset-rose-700">
<SelectValue className="flex-1 truncate placeholder-shown:italic" />
Expand Down
18 changes: 10 additions & 8 deletions packages/react-aria-components/src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,16 @@ function SelectInner<T extends object>({props, selectRef: ref, collection}: Sele
data-open={state.isOpen || undefined}
data-disabled={props.isDisabled || undefined}
data-invalid={validation.isInvalid || undefined}
data-required={props.isRequired || undefined} />
<HiddenSelect
autoComplete={props.autoComplete}
state={state}
triggerRef={buttonRef}
label={label}
name={props.name}
isDisabled={props.isDisabled} />
data-required={props.isRequired || undefined}>
{renderProps.children}
<HiddenSelect
autoComplete={props.autoComplete}
state={state}
triggerRef={buttonRef}
label={label}
name={props.name}
isDisabled={props.isDisabled} />
</div>
</Provider>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ export const AutocompleteMenuInPopoverDialogTrigger = {
let manyItems = [...Array(100)].map((_, i) => ({id: i, name: `Item ${i}`}));

export const AutocompleteSelect = () => (
<Select style={{marginBottom: 40}}>
<Select style={{marginBottom: 40, position: 'relative'}}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume these story changes are just to make sure nothing else changes with the addition of the style? I'm not able to reproduce the original issue on main in these stories so I'm assuming these didn't match the required conditions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, it's more about making sure that all instances and uses of it ourselves showcase the correct setup

<Label style={{display: 'block'}}>Test</Label>
<Button>
<SelectValue />
Expand Down
2 changes: 1 addition & 1 deletion packages/react-aria-components/stories/Form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const FormAutoFillExample = () => {
<Label>Zip</Label>
<Input name="city" type="text" id="city" autoComplete="shipping postal-code" />
</TextField>
<Select name="country" id="country" autoComplete="shipping country">
<Select style={{position: 'relative'}} name="country" id="country" autoComplete="shipping country">
<Label>Country</Label>
<Button>
<SelectValue />
Expand Down
10 changes: 5 additions & 5 deletions packages/react-aria-components/stories/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default {
};

export const SelectExample = () => (
<Select data-testid="select-example" id="select-example-id">
<Select data-testid="select-example" id="select-example-id" style={{position: 'relative'}}>
<Label style={{display: 'block'}}>Test</Label>
<Button>
<SelectValue />
Expand All @@ -43,7 +43,7 @@ export const SelectExample = () => (
);

export const SelectRenderProps = () => (
<Select data-testid="select-render-props">
<Select data-testid="select-render-props" style={{position: 'relative'}}>
{({isOpen}) => (
<>
<Label style={{display: 'block'}}>Test</Label>
Expand All @@ -67,7 +67,7 @@ export const SelectRenderProps = () => (
let manyItems = [...Array(100)].map((_, i) => ({id: i, name: `Item ${i}`}));

export const SelectManyItems = () => (
<Select>
<Select style={{position: 'relative'}}>
<Label style={{display: 'block'}}>Test</Label>
<Button>
<SelectValue />
Expand All @@ -85,7 +85,7 @@ export const SelectManyItems = () => (
);

export const VirtualizedSelect = () => (
<Select>
<Select style={{position: 'relative'}}>
<Label style={{display: 'block'}}>Test</Label>
<Button>
<SelectValue />
Expand Down Expand Up @@ -138,7 +138,7 @@ export const AsyncVirtualizedCollectionRenderSelect = (args) => {
});

return (
<Select>
<Select style={{position: 'relative'}}>
<Label style={{display: 'block'}}>Async Virtualized Collection render Select</Label>
<Button style={{position: 'relative'}}>
<SelectValue />
Expand Down
2 changes: 1 addition & 1 deletion starters/tailwind/src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function Select<T extends object>(
{ label, description, errorMessage, children, items, ...props }: SelectProps<T>
) {
return (
<AriaSelect {...props} className={composeTailwindRenderProps(props.className, 'group flex flex-col gap-1')}>
<AriaSelect {...props} className={composeTailwindRenderProps(props.className, 'group flex flex-col gap-1 relative')}>
{label && <Label>{label}</Label>}
<Button className={styles}>
<SelectValue className="flex-1 text-sm placeholder-shown:italic" />
Expand Down