reason-react icon indicating copy to clipboard operation
reason-react copied to clipboard

Allow data-* in DOM elements

Open chenglou opened this issue 6 years ago • 16 comments

aria-foo is supported through ariaFoo, because we exhaustively list all the aria options. data-* is dynamic. I think it's fine to use cloneElement to add them as an escape hatch.

chenglou avatar May 27 '18 01:05 chenglou

It would be very unfortunate b/c I will need to clone all interactive elements in components library to make them findable in integration tests.

alex35mil avatar May 27 '18 06:05 alex35mil

One more case I faced today: I'm almost finished bindings to react-beautiful-dnd and I ended up cloning every droppable & draggable element on application side b/c this lib requires specific data- attribute to be set. I don’t think it’s going to be a perf win.

alex35mil avatar May 30 '18 18:05 alex35mil

maybe having a little abstraction could be enough?

let withDataAttributes = (~data, element) =>
  ReasonReact.cloneElement(
    element,
    ~props=Obj.magic(Js.Dict.fromList(data)),
    [||],
  );

let div =
  withDataAttributes(
    ~data=[("data-foo", "bar"), ("data-bar", "baz")],
    <div />,
  );

ReactDOMRe.renderToElementWithId(div, "preview");

bloodyowl avatar May 31 '18 17:05 bloodyowl

We make heavy use of data-* due automation purposes. Telling our more designer oriented developers that now they need to use cloneElement whenever they have to add some data-* attribute seems that is going to be a hard sell. So some form of sugar specific for data-* attributed will be very welcome.

Will something https://github.com/reasonml/reason-react/issues/196#issuecomment-375663193 be possible?

rafayepes avatar Jun 15 '18 15:06 rafayepes

I have the same issue @rafayepes describes

kennetpostigo avatar Jun 15 '18 15:06 kennetpostigo

looked a bit at what we could do right now and bumped into a few issues that'd make it non-trivial.

I tried to wrap the createElement FFI in a function that checks if a dataSet field exists in props and overloads the object, but the [@bs.splice] constrain complains about that because it requires an syntactic array as last argument. would there be a way to "transfer" the splice properties to a non-FFI ? (cc @bobzhang)

Another way would be to allow passing a transformer function to a field in [@bs.deriving abstract], not sure how difficult that would be though.

And a possible third alternative I see would be to allow an "unsafe spread" directly in JSX:

<div
   ...{"data-foo": "bar"}
/>

bloodyowl avatar Jun 17 '18 09:06 bloodyowl

Could you not add an unsafe option for edgecases? <div prop=("data-stuff", "some_stuff") /> There are lots of scenarios where people are using non standard html properties for all sorts of things.

cullophid avatar Jun 17 '18 13:06 cullophid

this would require some changes on bs.deriving abstract or FFI propagation AFAIK

bloodyowl avatar Jun 17 '18 20:06 bloodyowl

Is there at present a recommended solution for using data attributes?

apolishch avatar Sep 24 '18 23:09 apolishch

Ran into the problem with cypress needing custom data-* attributes for e2e testing. It would be really great if we didn't have to rely on cloneElement for this.

rudolfs avatar Sep 17 '19 08:09 rudolfs

Is there a reason not to add something like data: Js.Obj.t?

<button data={"attrName": "attrValue"}> </button>

rusty-key avatar Dec 06 '19 03:12 rusty-key

Guessing not zero cost.

Workaround from @yawaramin works pretty well until there’s official solution:

module WithTestId = {
  [@react.component]
  let make = (~id: string, ~children) =>
    ReasonReact.cloneElement(children, ~props={"data-test-id": id}, [||]);
};

<WithTestId id="foo"> <button /> </WithTestId>

alex35mil avatar Dec 06 '19 06:12 alex35mil

Hey @alexfedoseev

Would you mind creating a PR and adding that to the docs? This is an awesome workaround for now.

Thank you!

peterpme avatar Apr 22 '20 22:04 peterpme

Hey everyone, we've added an example here: https://reasonml.github.io/reason-react/docs/en/adding-data-props

peterpme avatar Apr 27 '20 22:04 peterpme

I was thinking of making its own abstraction to Spread component? @peterpme for instance like special ownProps attribute which takes the object and spread it on creation? but idk

heygema avatar May 08 '20 04:05 heygema

Hey @heygema open up a PR and we can take a look :smile:

peterpme avatar May 08 '20 15:05 peterpme