adobe / adobe/react-spectrum

useSlottedContext should not throw when slot is not found

Open
#9,283 4 comments 1 reaction 0 assignees View on GitHub
Dominant language
TypeScript
Stars
15.9k
Forks
1.6k
Avg merge
3d 9m
Merged PRs (30d)
59

Description

### Provide a general summary of the issue here

Referring to this code:

```ts
if (!ctx.slots[slotKey]) {
let availableSlots = new Intl.ListFormat().format(Object.keys(ctx.slots).map(p => `"${p}"`));
let errorMessage = slot ? `Invalid slot "${slot}".` : 'A slot prop is required.';

throw new Error(`${errorMessage} Valid slot names are ${availableSlots}.`);
}
```
https://github.com/adobe/react-spectrum/blob/main/packages/react-aria-components/src/utils.tsx#L171-L176

This violates Open/Close principle, so that it hinders the ability to compose and add new slots in extended components.

Using `Button` as example, I want to add a `clear` slot and use the button to clear the text in a input field:

```tsx

```

```tsx
export function ClearButton() {
return X
}
```

```tsx
export const StyledButtonContext = createContext>(null)

export const StyledButton = forwardRef(props, ref) {
;[props, ref] = useContextProps(props, ref, ButtonContext]
;[props, ref] = useContextProps(props, ref, StyledButtonContext]

return
}
```

```tsx
export function InputField({ children }) {
return (

{children}

)
}
```

Since the props `{ slot: 'clear' }` is eventually passed to `useSlottedContext`, it throws.

Workaround this requires manually picking out `slot: 'clear'` in the `StyledButton`, breaking encapsulation and OCP.

Something like:

```tsx
export const StyledButton = forwardRef(props, ref) {
const { slot, ...rest } = props

let baseButtonProps = slot === 'clear' ? rest : props

;[props, ref] = useContextProps(baseButtonProps, ref, ButtonContext]
;[props, ref] = useContextProps({ slot, ...props}, ref, StyledButtonContext]

baseButtonProps = slot === 'clear' ? rest : props

return
}
```

You can see this is not scalable as more slots are used in the system.

### 🤔 Expected Behavior?

return `undefined`

### 😯 Current Behavior

throw error

### 💁 Possible Solution

_No response_

### 🔦 Context

See above

### 🖥️ Steps to Reproduce

Hopefully the example above should be clear enough.

### Version

1.13.0

### What browsers are you seeing the problem on?

Chrome

### If other, please specify.

_No response_

### What operating system are you using?

macos

### 🧢 Your Company/Team

Palo Alto Networks

### 🕷 Tracking Issue

_No response_

Contributor guide

Open the contributing guide

Research direction

Start in packages/react-aria-components/src/utils.tsx at useSlottedContext, especially the logic around lines 171–176, and trace it through the Button and context composition shown in the issue. Done means a missing clear slot no longer throws and the example can pass slot="clear"; run the relevant package tests to verify the behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.