adobe / adobe/react-spectrum

`useLabel`'s `labelProps` fails type-check when used with a `div`

Open
#7,269 2 comments 0 reactions 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

It seems `useLabel().labelProps` is typed in a way that only works on "`label`-like" elements.

While type-check works for `span`, it fails for a `div`.

### 🤔 Expected Behavior?

This should pass type-check:

```tsx
const { labelProps, fieldProps } = useLabel({ labelElementType: 'div' });

return (

I'm a label

);
```

### 😯 Current Behavior

It fails with the following (quite verbose) type-check error:

```
Type '{ children: string; id?: string | undefined; role?: AriaRole | undefined; tabIndex?: number | undefined; style?: CSSProperties | undefined; className?: string | undefined; ... 219 more ...; onTransitionStartCapture?: TransitionEventHandler<...> | undefined; } | { ...; }' is not assignable to type 'DetailedHTMLProps, HTMLDivElement>'.
Type '{ children: string; form?: string | undefined; htmlFor?: string | undefined; defaultChecked?: boolean | undefined; defaultValue?: string | number | readonly string[] | undefined; suppressContentEditableWarning?: boolean | undefined; ... 271 more ...; onTransitionStartCapture?: TransitionEventHandler<...> | undefined...' is not assignable to type 'DetailedHTMLProps, HTMLDivElement>'.
Type '{ children: string; form?: string | undefined; htmlFor?: string | undefined; defaultChecked?: boolean | undefined; defaultValue?: string | number | readonly string[] | undefined; suppressContentEditableWarning?: boolean | undefined; ... 271 more ...; onTransitionStartCapture?: TransitionEventHandler<...> | undefined...' is not assignable to type 'HTMLAttributes'.
Types of property 'onToggle' are incompatible.
Type 'ToggleEventHandler | undefined' is not assignable to type 'ToggleEventHandler | undefined'.
Type 'ToggleEventHandler' is not assignable to type 'ToggleEventHandler'.
Property 'align' is missing in type 'HTMLLabelElement' but required in type 'HTMLDivElement'.
```

### 💁 Possible Solution

`labelProps` are currently typed as:

```tsx
export interface LabelAria {
labelProps: DOMAttributes | LabelHTMLAttributes,
// ...
```

While only `{ id: string, htmlFor?: string }` is returned.

---

One approach can be to narrow down the type, to just what we know we return, but I can see how that can be undesirable, as it can make changing the API surface in the future harder.

---

Another approach can be to make the returned type depend on the optional `labelElementType` key:

https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAJQKYEMDGMA0cDecAyKARkgDYASAKgLL4CCMMUwRArjEgM5wC+cAZlAgg4AciioMogNwAoUJFi44AEQDy1BkxbsuvAUJGiAAhPQwAtDACeYLgHpOACxQSAJjNlebdgsTJ0zCgACkJgnAA8lHBIAB4cAHZu3ADWSNYQ-HBUtACipEggSAkwlCgA5gByKEXUKGAAfHAAvLJw7XDRcYnJYqT+pKJwAPy4bR0T-SSk+YXFpbZIwwBcnXITfKs44xPtU2SzRSWUi6uUmDu8cvIlSFD86Eh+04HAKFEx8cW9aRlZOfhDvMylUakg6o0xpMBqEIOFVupNIxmGwONwAD7PMgArQo3SRAFA44Vaq1eoAbUoAF0GnIeF5+KwEhhgBAEnBWJwkIRph9ut9UulMtkaICCkdSiSwRCWn0BqIGgAKMBhTirHkBIKw8JRBoASnVA1e70otK8aDZnHgeH2pG13D4zQ5XI1pEVOB4erkFoSVuUtvtq1trvt+idnO5A3dcFtRIWdlWoltQ093st1pjMNVq04YBQCRDqrDzsj02jsfFwNOYlz+ZTXtkPr9NqzcLVcDcwAAboW28WI67ywM4ycE2JO1369cm-B6AAhXL4WURW24AB0G4Dqr4OA3a+DrfCPAaKEz0zPZAi9ltZpnqgAkgA1WWKy4RCcNS4Td-d9cbie9keDTOBArCkG4cAkHAEApFeH5fh0P5drum6Hpwx4gWBEEPMApBwd2n7fvY8ENneADKwR0JUy61uyKFrrRgHoSecC0ReeGOHmCS0kAA

(Notice the change from `ElementType` to `keyof HTMLElementTagNameMap`, so we can correctly index it with `T`)

### 🖥️ Steps to Reproduce

https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4AoUSWOAbzgFcBnJAGRQCMkAbOAXzjZcBIuhgBaFFGAoy5cmggA7JvHrdOPAAo4wTAFxwAJsABu7Ltx0Q9-OAF5GLCzwAU6zdwCi3JCCRKMAAqAJ5gSIb4Jqb4-ACUFIoqanAaltZ6hkxgKEouVrpMdo7MbJ7uqZ4+fgHBYREE2bmxfAnySapwTUoOcAA83XQAdCPd+RlMfAB8KF05PWk8fQD03VOJyp3RvX3btCND0eOF07Pbi9wr0etAA

```tsx
function SomeComponent() {
const { fieldProps: divFieldProps, labelProps: divLabelProps } = useLabel({
label: 'This is a div label',
labelElementType: 'div',
});
const { fieldProps: spanFieldProps, labelProps: spanLabelProps } = useLabel({
label: 'This is a span label',
labelElementType: 'span',
});

return (



This is a span label
This is what's being labelled



This is a div label

This is what's being labelled



);
}
```

### Version

Latest `react-aria`.

Contributor guide

Open the contributing guide

Research direction

Start from the useLabel API and reproduce the TypeScript error with the provided div and span examples. Trace the declared type of labelProps and verify that the div example passes type-check while the existing span example continues to work.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.