GithubHelp home page GithubHelp logo

Comments (16)

EthanStandel avatar EthanStandel commented on April 26, 2024 7

@gaearon I figured the naming scheme was to avoid any potential conflict. My preference would be an ID generation model that uses a non-special character wrapping or just a GUID.

e.g. REACTIDS1 or f2ba2bd18ae847a0beb78f57f58d836d

However, if the wrapping characters were changed from : (colon) to either - (dash) or _ (underscore) then the IDs at least wouldn't conflict with CSS.

e.g. _S1_ or -S1-

I know React itself isn't really supposed to be making changes specific to the web, but I do think underscores in particular are far less likely to conflict with other DSLs. I also feel like this is a good use-case for useId which is made more challenging because of this issue (this case is actually the first time I've needed useId, personally).

from react.

EthanStandel avatar EthanStandel commented on April 26, 2024 2

Hi I am Alfez mansuri. I am new to open source and just came across this issue and tried my hands on it. https://stackblitz.com/edit/react-ts-kvrc8e?file=Example.tsx Please go through this. I have added a function that removes the special characters from id.

That functionally works but... it's not really a good idea. The problem here is that React owns the generation of the ID. If you put this function in your code and then React changes how their ID generation implementation works and then you update React, you could end up with overlapping IDs. Like say that these become two separate IDs that React may return: as:df & as-df. Your function would convert them both to asdf, meaning that you'd have two copies of the same ID. If you use CSS.escape as is used in my example, there's no possible risk of that issue but of course CSS.escape doesn't work on the server. You could reimplement that, but you really shouldn't modify the ID.

In general though, this is definitely something that React must own the fix of so that the rest of us don't have to worry about it, or monkeypatch primitive hooks, or have to be concerned with how to handle the logic on the client & server separately for a DSL as commonly needed with React as CSS.

from react.

nksfrank avatar nksfrank commented on April 26, 2024 2

I would like to note if you'd like to select an element in the DOM where it has its ID generated by useId, you can do something like the following:

const buttonRight = containerElement?.querySelector(`[id="${buttonRightSelector}"]`);

https://github.com/typehero/typehero/blob/main/apps/web/src/components/carousel.tsx

Where buttonRightSelector is the string ID generated. Just a suggestion if you get stuck on it not working as a valid selector.

As an element id it works, as long as you are in JS. but not when you are trying to write a CSS selector. As #:gen-id: {} is not a valid CSS sector

from react.

devongovett avatar devongovett commented on April 26, 2024 1

To be clear, the ids generated by react are valid, and do work correctly for accessibility purposes. In your tests, you can use getElementById to find the element instead of querySelector with a manually prepended #. Alternatively if you need a more complex selector, the id can be escaped with the built in CSS.escape function:

document.querySelector(`#${CSS.escape(someId)} > .foo`)

from react.

beamery-tomht avatar beamery-tomht commented on April 26, 2024 1

Alternatively if you need a more complex selector, the id can be escaped with the built in CSS.escape function:

This is what we've had to do and cost us a lot of wasted time updating all of our tests to dodge this strange decision of putting colons in id values

from react.

nksfrank avatar nksfrank commented on April 26, 2024 1

it's unfortunate that : was selected as the delimiter. stops us from targeting the element within a inline style block

const breakpointMap = {
  base: 0,
  xs: 375,
  sm: 768,
  md: 1024,
  lg: 1128,
  xl: 1500,
  xxl: 1920,
} as const;
const keys = Object.keys(breakpointMap) as (keyof typeof breakpointMap)[];
export const MediaQuery = ({
  only,
  up,
  down,
  display = 'contents',
  children,
}: Props): JSX.Element => {
  const id = useId();
  const query = only
    ? `min-width: ${breakpointMap[only]}px and max-width: ${
        breakpointMap[keys[keys.indexOf(only) + 1]]
      }px`
    : up && down
    ? `min-width: ${breakpointMap[up]}px and max-width: ${breakpointMap[down]}px`
    : up
    ? `min-width: ${breakpointMap[up]}px`
    : `max-width: ${breakpointMap[down]}px`;
  return (
    <>
      <div id={id}>{children}</div>
      <style>{`
#${id} {
  display: none;
}
@media (${query}) {
  #${id} {
    display: ${display};
  }
}
      `}</style>
    </>
  );
};

result:

<div id=":S1:">
<style>
#:S1: {
  display: none;
}
@media (min-width: 1024px) {
  #:S1: {
    display: contents;
  }
}
</style>

from react.

maxdemaio avatar maxdemaio commented on April 26, 2024 1

I would like to note if you'd like to select an element in the DOM where it has its ID generated by useId, you can do something like the following:

const buttonRight = containerElement?.querySelector(`[id="${buttonRightSelector}"]`);

https://github.com/typehero/typehero/blob/main/apps/web/src/components/carousel.tsx

Where buttonRightSelector is the string ID generated. Just a suggestion if you get stuck on it not working as a valid selector.

from react.

Denis-Andreev avatar Denis-Andreev commented on April 26, 2024 1

Please fix it

from react.

gaearon avatar gaearon commented on April 26, 2024

I believe that's intentional to prevent collisions with manually chosen IDs.

Not sure if there's a more appropriate solution for your case.

from react.

dkryaklin avatar dkryaklin commented on April 26, 2024

In my project, I utilize adobe/react-spectrum, which has recently integrated React.useId() for generating IDs for elements. You can find an example of this integration here.

On the surface, this change appears harmless. However, a problem arises when the generated ID serves not only as a mere identifier but also as a link between various elements, such as in the case of the 'aria-labelledby' attribute.

For instance, consider the following example, which was valid before react-spectrum began utilizing React.useId():

notifications
  .getButton()
  .should('have.attr', 'aria-labelledby')
  .then((ariaLabelledBy) => {
    cy.get(`#${ariaLabelledBy}`)
      .should('match', 'label')
  });

As evident from the above code snippet, we do not have control over the button's ID or the 'aria-labelledby' value. Consequently, this code fails with the new version since the colon (:) is not a valid selector and causes cy.get to fail.

This situation begs the question: who should be responsible for supplying a valid ID value?

from react.

EthanStandel avatar EthanStandel commented on April 26, 2024

The reason I would argue that I think that it's reasonable for React to own this fix is that the id prop for HTML elements is the defacto use-case given in the React docs the the useId hook.

Also React owns useInsertionEffect which they say is specifically for supporting CSS-in-JS libraries.

So I don't think that useId IDs being able to be used in HTML and referenced in CSS (or Cypress queries) should be considered outside of the bounds of React's responsibilities.

from react.

beamery-tomht avatar beamery-tomht commented on April 26, 2024

Accessibility libraries are using useId here to generate unique IDs on elements that are referenced

The cypress test above looks to be testing an accessibility criteria that the id should match the value of an aria-labelledby element

This can also apply for many other accessibility criteria such as:

  • htmlFor
  • aria-owns
  • aria-controls
  • aria-describedby
  • aria-activedescendant
  • etc....

It's then reasonable to assume that consumers of the library would be testing that these implementations of a11y attributes are rendered correctly... as they would aim to be library agnostic of course... and now each consumer will face these invalid characters in the unique ID...

Why not just make the IDs use valid characters...?

Are you suggesting that libraries should write their own useId implementation for unique ID generation so that they can support these a11y criteria? That would give them complications for consistent IDs on server side rendering - I'd assume it would make sense to support their use case with the inbuilt hook

from react.

EthanStandel avatar EthanStandel commented on April 26, 2024

But in terms of generating CSS (which you may want to do by creating a style element which may happen on the server), you may not have access to CSS.escape. Plus, it's kind of weird that we should have to escape it in the fairly common use-case of a CSS query.

from react.

AMalfez avatar AMalfez commented on April 26, 2024

Hi
I am Alfez mansuri.
I am new to open source and just came across this issue and tried my hands on it.
https://stackblitz.com/edit/react-ts-kvrc8e?file=Example.tsx
Please go through this.
I have added a function that removes the special characters from id.

from react.

maxdemaio avatar maxdemaio commented on April 26, 2024

I would like to note if you'd like to select an element in the DOM where it has its ID generated by useId, you can do something like the following:

const buttonRight = containerElement?.querySelector(`[id="${buttonRightSelector}"]`);

https://github.com/typehero/typehero/blob/main/apps/web/src/components/carousel.tsx
Where buttonRightSelector is the string ID generated. Just a suggestion if you get stuck on it not working as a valid selector.

As an element id it works, as long as you are in JS. but not when you are trying to write a CSS selector. As #:gen-id: {} is not a valid CSS sector

Yes I totally agree. Just thought I'd put this on this thread because I had some difficulty selecting the element in JS until I found this ๐Ÿ‘๐Ÿป

from react.

erikasby avatar erikasby commented on April 26, 2024

Agree on changing : to something else - can't see a reason to leave current solution as an ideal one (It works, but seems like not as everyone expects it to). I guess React shouldn't break browsers native functionality?
Edit: with deleted part I meant if everyone expects useId to just work seamlessly with the browsers' syntax, then it most likely should.

I believe there are many ways to ...

... prevent collisions with manually chosen IDs

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.