React: feat: allow multiple opaque identifiers in HTML attributes

Created on 13 Apr 2020  路  6Comments  路  Source: facebook/react

react version: #17322
Original: https://github.com/facebook/react/pull/17322#issuecomment-613104823

Currently only a single value from useOpaqueIdentifier (unreleased) can be passed to HTML attributes. However, there are HTML attributes which support multiple ids (IDREFS) like aria-labelledby. This can be used to implement various patterns such as:
```jsx
export default function App() {
const taxpayerId = React.unstable_useOpaqueIdentifier();
const spouseId = React.unstable_useOpaqueIdentifier();
const w2GrossId = React.unstable_useOpaqueIdentifier();
const dividendsId = React.unstable_useOpaqueIdentifier();
return (




    <tr>
      <th id={w2GrossId}>W2 Gross</th>
      <td>
        <input type="text" aria-labelledby={[taxpayerId, w2GrossId]} />
      </td>
      <td>
        <input type="text" aria-labelledby={[spouseId, w2GrossId]} />
      </td>
    </tr>

    <tr>
      <th id={dividendsId}>Dividends</th>
      <td>
        <input type="text" aria-labelledby={[taxpayerId, dividendsId]} />
      </td>
      <td>
        <input type="text" aria-labelledby={[spouseId, dividendsId]} />
      </td>
    </tr>
  </tbody>
</table>

);
}
````
-- https://codesandbox.io/s/useopaqueidentifier-for-idrefs-ocnm4

This example is from https://www.w3.org/WAI/GL/wiki/Using_aria-labelledby_to_concatenate_a_label_from_several_text_nodes

This currently almost works but it concatenates the ids with "," (default toString of arrays) instead of " ".

<button aria-labelledby={[opaqueIdentifier1, opaqueIdentifier1]} /> is to me the most intuitive one since we're passing a list of ids.

Edit:
Removed the collapsible listbox example since that pattern has some a11y issue.

DOM

Most helpful comment

@eps1lon I believe you can safely get around this for now by using a custom class that extends Array and overrides toString.

All 6 comments

I like the API of using an array of opaque identifiers. You could make the argument that React should always join arrays passed to DOM attributes with a space, since the HTML spec defines the space as the list delimiter. This would be a breaking change though.

One alternative would be iterating through every array passed to an attribute and checking that each item is an opaque identifier, but that's a lot of potentially wasted work.

Maybe a special value like React.createIdentifierList that React could check for and serialize differently?

@eps1lon I believe you can safely get around this for now by using a custom class that extends Array and overrides toString.

Maybe a special value like React.createIdentifierList that React could check for and serialize differently?

Which also has the upside that it won't trigger jsx-a11y/aria-proptypes or TypeScript type errors (we would need to claim that opaque identifiers are strings for TS to accept it. On the other hand we need to change types anyway for useOpaqueIdentifier) .

Having the array shorthand is definitely nice but I think having an explicit createIdentifierList is safer long term.

@aweary Seems like your approach only works for .render. It throws during hydration (using .hydrate with

The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly.

-- https://codesandbox.io/s/serverless-tdd-7ltt5

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

Bump

Was this page helpful?
0 / 5 - 0 ratings