facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
229.1k stars 46.87k forks source link

Allow custom (nonstandard) attributes. #140

Closed steida closed 7 years ago

steida commented 11 years ago

Various frameworks uses custom attributes. React could allow to extend default data- and aria- prefixes. Something like this:

React.registerCustomAttributePrefix('e-');
React.registerCustomAttributePrefix('ng-');
sophiebits commented 9 years ago

data-pin-nopin="true": https://github.com/pinterest/widgets/issues/29

sebmarkbage commented 9 years ago

Nice @spicyj! Problem solved. I figured I should've checked for alternatives but I'm sick in bed and also lazy.

Gozala commented 9 years ago

@sebmarkbage @spicyj this maybe solving this specific instance but it is still a very painful issue for some of us. We are basically forced to do a horrible hacks to workaround lack of general attribute support. I have wrote about this in #2746 and also explained workardounds we employ.

I would very much like for this issue to be resloved maybe for the very least react can be made configurable so users could extend the whitelist.

sophiebits commented 9 years ago

@Gozala Yes, we understand. That's why this issue is still open.

pencilcheck commented 9 years ago

Using angular material with react and attributes such as "layout" that are introduced in angular material doesn't work. How do I whitelisted those attributes for the moment? https://material.angularjs.org/latest/#/layout/container

chromakode commented 9 years ago

Based on @nfroidure's approach above, for server-side rendering (e.g. rendering archaic table attributes in HTML emails), here's a workaround I'm experimenting with using in the meantime:

var DOMProperty = require('react/lib/ReactInjection').DOMProperty
DOMProperty.injectDOMPropertyConfig({
  Properties: {
    'valign': DOMProperty.MUST_USE_ATTRIBUTE,
  }
})
terinjokes commented 9 years ago

With 0.14 splitting react-dom from react, could an alternative module be created to allow these archaic HTML attributes (react-dom-emails or something of the like)?

IL55 commented 9 years ago

I just want to notify that in React 0.13.3, still hasn't support for svg "mask" attribute. Please don't mix up with mask tag, i.e. next is allowed:

      <defs>
           <mask id="myMask"> .... </mask>
      </defs>

but using mask is not possible (react 0.13.3 removes that attribute)

    <g mask="url(#myMask)"> ... </g>

Here is jsfiddle example: https://jsfiddle.net/kbcpLyax/3/

More details could be found in next comment: https://github.com/facebook/react/issues/140#issuecomment-73788054

quantizor commented 9 years ago

@IL55 i'd open a separate ticket for it

PetrochukM commented 9 years ago

React 13.3 strips my Animate tag.

From:

<animate attributeName="stop-color" dur="24s" values="rgba(0,0,12,0);rgba(25,22,33,.3);rgba(32,32,44,.8);rgb(58,58,82);rgb(81,81,117);rgb(138,118,171);rgb(205,130,160);rgb(234,176,209);rgb(235,178,177);rgb(177,181,234);rgb(148,223,255);rgb(103,209,251);rgb(56,163,209);rgb(36,111,168);rgb(30,82,142);rgb(91,121,131);rgb(157,166,113);rgb(233,206,93);rgb(178,99,57);rgb(47,17,7);rgb(36,14,3);rgb(47,17,7);rgba(75,29,6,.4);rgba(21,8,0,0);rgba(0,0,12,0)" repeatCount="indefinite"></animate>

To:

<animate data-reactid=".0.0.1.$=10:0.$=10:0.$=10:0.$=11:0"></animate>

Any ideas on how I can overcome this?

suryagaddipati commented 9 years ago

@Deepblue129 you can do ref.getDomNode().setAttribute(... in component lifecycle method.

despairblue commented 9 years ago

This also makes it impossible to use react to generate x3d scenes like

<transform>
  <inline url={url} namespace={url}/>
</transform>

and having these rendered using x3dom or later natively by the browser

Most attributes will be stripped from the rendered content, like translations or rotations, or even url for the inline node above.

almirfilho commented 9 years ago

It doesn't allow tabindex attribute too. So it's impossible to follow the W3C WCAG Spec SCR29 to enhance accessibility in non focusable elements by default, like a simple <div>.

syranide commented 9 years ago

@almirfilho tabIndex and it'll work just fine.

almirfilho commented 9 years ago

@syranide thanks for the tip!

eyworldwide commented 9 years ago

@chromakode thx! it works in my project...

chrissheppard41 commented 8 years ago

Hi,

Might be worth taking a look at supporting googles Rich snippet https://developers.google.com/structured-data/rich-snippets/?hl=en

Just a possible idea

dantman commented 8 years ago

@chrissheppard41

Might be worth taking a look at supporting googles Rich snippet https://developers.google.com/structured-data/rich-snippets/?hl=en

Microdata, RDFa, and script tags are already supported.

chrissheppard41 commented 8 years ago

@dantman

Yeah I read this: https://facebook.github.io/react/docs/tags-and-attributes.html

But when I embed say "itemscope" or any others like so:

    render() {
        return (
            <div ref="parent" className="review_feed" itemscope="" itemtype="http://schema.org/Product">
                ...Something here
            </div>
        );
    }

It prints out:

<div class="review_feed" data-reactid=".0">
    ...Something here
</div>

It's not applying to the dom

This is likely to my misunderstanding but some clarity would be lovely. Thanks.

dantman commented 8 years ago

@chrissheppard41 That's because React-JSX is not HTML. You converted the html class to React's className but didn't do the same for the rest of the attributes.

You need to convert the HTML examples to React-JSX:

<div class="review_feed" itemscope="" itemtype="http://schema.org/Product">
  ...Something here
</div>

Becomes:

<div itemType="http://schema.org/Product" itemScope className="review_feed">
  ...Something here
</div>
chrissheppard41 commented 8 years ago

Ah, I'm sorry, that worked, Thank you.

monolithed commented 8 years ago

I really don't understand why some library should restrict my application architecture?

antitoxic commented 8 years ago

@spicyj @sebmarkbage @syranide

So far, from what I've read, this looks like a real problem, not just a feature perk.

Is there a downside for React, before an ideal solution is provided, to supply some intermediate one?

Like:

<div thirdpary-attr='"i need this" allowAttrs="thirdpary-attr">
<!-- or previously defined -->
<div thirdpary-attr='"i need this" allowAttrs={this.allowedAttrs}/>
<!-- or -->
<div thirdpary-attr='"i need this" safeAttrs="thirdpary-attr">

I understand that the above is not the wisest thing to do with an API (introduce a temporary interface) but consider the issue is 2 years old. Even the best APIs I know change in that time.

If however, you completely disagree, could React documentation be changed so that it includes a workaround? That will be super-useful.

antitoxic commented 8 years ago

PS: Aside from use-cases given above (+ others things like https://github.com/facebook/react/issues/3809) I'm using attributes for something that people can call me heretic - simply for clear way of styling (i.e. .myCSSComponentClass[size="big"]) . Combining attributes and their values has proven to be way more readable than just throwing classes in and it's DRY-er than 'classnames({..})' which simply repeats properties most of the time.

For that purpose I'm using a simple ES7 decorator.

decorators.js:

import ReactDOM from 'react-dom';

export function customAttributes(...attrs) {
    return function(component) {
        var originalComponentDidMount = component.prototype.componentDidMount;
        component.prototype.componentDidMount = function() {
            if (originalComponentDidMount) originalComponentDidMount.apply(this, arguments);
            var rootDom = ReactDOM.findDOMNode(this);
            attrs.map(attr => {
                if (!this.props.hasOwnProperty(attr)) return;
                if (this.props[attr] == false && rootDom.hasAttribute(attr)) {
                    rootDom.removeAttribute(attr);
                    return;
                }
                rootDom.setAttribute(attr, this.props[attr])
            });
        };
        return component;
    }
}

button.js:

import React from 'react';
import {customAttributes} from 'decorators';

@customAttributes('color', 'size')
export class Button extends React.Component {
...
}

To me ot looks like a clean approach. Am I doing something terribly akward? Is this a reccomended approach?

ajfarkas commented 8 years ago

Looking forward to this fix. Would like to use SVG Icons, but dangerously setting xlink:href is a bummer.

sophiebits commented 8 years ago

@ajfarkas xlinkHref={...} works already in 0.14.

ajfarkas commented 8 years ago

true, but <use> tags don't.

I appreciate the attempt at giving people a heads up, but this is producing a major headache, since I have to change all of my SVG code, then will have to change it back once this gets updated.

sophiebits commented 8 years ago

<use> tags (and all SVG tags and attributes) should work in master and will work in v15.

What do you mean about changing your code?

tnrich commented 8 years ago

Hey there, Props on making react, its awesome! Pun intended :)

I'm trying to use the "inert" html attribute to disable a div (and polyfilling it so it works on all browsers), but react doesn't seem to be letting it through. Is there any way to get this to work currently?

Thanks!

gaearon commented 8 years ago

@tnrich

For not yet supported attributes, you can put ref on the element and call setAttribute() manually.

For example:

return <div ref={node => node && node.setAttribute('inert', '')} />
tnrich commented 8 years ago

Awesome thanks @gaeron !

On Thu, Feb 18, 2016, 6:00 PM Dan Abramov notifications@github.com wrote:

@tnrich https://github.com/tnrich

For not yet supported attributes, you can put ref on the element and call setAttribute() manually.

For example:

return <div ref={node => node && node.setAttribute('inert', '')} />

— Reply to this email directly or view it on GitHub https://github.com/facebook/react/issues/140#issuecomment-186010590.

dantman commented 8 years ago

@tnrich inert was dropped from the standard drafts some time ago; it's not a pending standard.

tnrich commented 8 years ago

@dantman, that may be so, but, is there a reason not to use it with a polyfill (kind of a misnomer in this case), given the listed caveats?

Here's the npm module I'm using: https://github.com/GoogleChrome/inert-polyfill

Sorry to stray off topic everyone..

fritx commented 8 years ago

If you want to use a custom attribute, you should prefix it with data-.

But seems nwjs only recognizes nwsaveas, nwworkingdir (cannot have extra prefix), etc.

// adding data- prefix would break
<input type="file" nwsaveas="filename.txt" nwworkingdir="C:\\Windows" />

What could I do with this? Thanks!

jayphelps commented 8 years ago

@fritx https://github.com/facebook/react/issues/140#issuecomment-62527758

fritx commented 8 years ago

@jayphelps thanks for pointing out the comment (there were too many to figure out)

until there's movement on this.

So there is still some movement on this?

I had tried that workaround before and it did work util later. But I've just found another issue https://github.com/nwjs/nw.js/issues/3372#issuecomment-147936759

Thanks to that buddy's great effort. I guess it's some problem of nwjs itself.

fritx commented 8 years ago

I still wonder is a.setAttribute('xxx') entirely equivalent to <a xxx> stuff, or is there still some tiny difference between the two definition?

Btw, git-blame-someone-else is awesome. I just plan to fake some funny commit in my own prj :smile: @janhancic

jayphelps commented 8 years ago

@fritx using setAttribute inside componentDidMount is different than using React's JSX/virtual DOM in the sense that it happens after the element has already been inserted into the DOM. Depending on how that library works, that might impact things.

I find that often, when you decide it's worth it to integrate a library that is incompatible with React, it's best to just create a wrapper React Component and then just create the real nodes/use plugins and insert them inside componentDidMount, just like you'd do with regular JavaScript/jQuery; but remember to clean them up in componentWillUnmount. This isn't ideal, but I personally take a "reality isn't always ideal" approach to getting work done.

Also--I don't personally have knowledge of progress on react supporting arbitrary attributes, other than what's been discussed here.

fritx commented 8 years ago

Btw, git-blame-someone-else is awesome.

As a bash beginner, I had to do kind of research, until I eventually created git-green-someone-else, which was heavily inspired by git-blame-someone-else.

Hope any guy will enjoy it! And if I'm missing something, let me know.

PS: I'm fond of taking friends --force to my project so it looks active LOL..

poscar commented 8 years ago

Another use for this is for using React to perform server side rendering of Google AMP pages. Google AMP requires a <html ⚡></html> or <html amp></html>. More info here.

Currently react removes the amp attributes.

Thoughts?

dantman commented 8 years ago

I think the ReactInjection.DOMProperty interface is really nice. In the future if that interface was polished and made into a public interface when the devs are happy with its stability; I think it would make for a very good solution to this issue.

The range of nonstandard properties with reason to be used in react is fairly narrow. If we had that interface, then we could just create libraries that would inject support for nonstandard properties and attributes into react.

A react-nw library could inject nw* attributes; a react-amp library could inject amp attributes; and a react-angular library could not just support ng-* attributes, but perhaps support them as actual properties such as ngModel. And these kinds of libraries could do more than just whitelisting attributes, they could better integrate React with the library they're tied to.

sebmarkbage commented 8 years ago

What if there's both react-angular and react-ng libraries both integrating using the same attributes?

dantman commented 8 years ago

@sebmarkbage Then they'd be conflicting libraries and you could only use one of them. Just like if you tried to use Angular twice or another library that used ng-* attributes in the dom; or if you used two React components that defined and used a string type context parameter named foo for two different purposes.

poscar commented 8 years ago

Sadly the following snippet does not work for me:

const DOMProperty = require('react/lib/ReactInjection').DOMProperty;
DOMProperty.injectDOMPropertyConfig({
  Properties: {
    amp: DOMProperty.MUST_USE_ATTRIBUTE
  },
  isCustomAttribute: (attributeName) => {
    return attributeName === 'amp';
  }
});

Any ideas why?

I'll have to resort to doing string replacement, if I can't get React to allow this attribute. :(

UPDATE (05/2016): Turns out the workaround wasn't working because it wasn't being applied to the React module actually loaded by the dependency of my project. I managed to get the workaround above to work.

sebmarkbage commented 8 years ago

The server renderer not having an alternative way to fix this particular problem is unfortunate. We should fix that in isolation. Spawned a new issue. https://github.com/facebook/react/issues/6798

SunnyGurnani commented 8 years ago

Is there any update on this?

benjdlambert commented 8 years ago

@jayphelps is 100% spot on.

I had a real pain trying to work out a shocker of a bug recently. With the addition of the new playsinline to iOS10, if you put it in componentDidMount and the src attribute is already on the element from the render() it will not play inline.

I guess its kind of a bug from Safari point of view, but this is just one use case.

There will be other cases where adding elements after the element has already been inserted into the DOM which cause issues.

I fixed this, by using the is property on the element, which removes validation of props.

/blam

jayphelps commented 8 years ago

@benjdlambert I think you meant someone else, my only comment was linking to someone elses comment. 😄

benjdlambert commented 8 years ago

@jayphelps I meant the comment after your link to the comment 👍

nhunzaker commented 8 years ago

FWIW, I've been maintaining (sort of) a PR to remove the attribute whitelist:

https://github.com/facebook/react/pull/7311

I don't speak for the React team but, hopefully, if the decision is made to support custom attributes by eliminating the whitelist, this handles much of the legwork.