-
Notifications
You must be signed in to change notification settings - Fork 46.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow custom (nonstandard) attributes. #140
Comments
Cross-post from #1730 Have we considered something like an I like it in the sense that it would work like |
@syranide That's definitely an option to consider, imo (for whatever its worth :P ). It would certainly contribute to making this much less ambiguous or esoteric for new users. |
@syranide, now, that being said, are you referring to using It might be a good idea (especially for users who aren't familiar with ReactJS) to use something like properties suffixed by |
@Swivelgames Not sure if I understand, my intention with |
OH, I see what you're saying. I apologize, I misunderstood :) |
This is also an issue for interop between React and Custom Elements - something like an |
Do you guys know when this feature is going to land in React? I'm playing around with node-webkit, which supports a custom attribute |
@janhancic |
Yep, that's what I came up with :) Thanks. |
I don't think the workaround @syranide outlined will work in all the necessary cases. For example, I don't believe you can do:
And have it be properly upgraded as a "my-button" custom element. I assume because we're setting the |
Good find @Aaronius! I'd love for an official way to do this before the element is added into the DOM |
Sadly, the method described above doesn't work server side. A Is it feasible to create a |
Here is the solution i came accross https://github.com/SimpliField/react/commit/8861a9461c0f4dbac2c6dfb1bfe71a4d8c5fc356. It allowed me to inject custom attributes for my needs with this piece of code: var HTMLDOMLegacyPropertyConfig = {
isCustomAttribute: function(attributeName) {
return -1 !== [
'align', 'bgcolor', 'border'
].indexOf(attributeName);
},
Properties: {
align: null,
bgcolor: null,
border: null
},
DOMAttributeNames: {
},
DOMPropertyNames: {
}
};
var React = require('react');
// Allow custom/legacy attributes for mail templates
React.Injection.DOMProperty.injectDOMPropertyConfig(HTMLDOMLegacyPropertyConfig); Any better way to inject this ? If no, any plan on exposing ReactInjection on the React main object ? |
Just came across the same issue... The workaround mentioned by @syranide won't work on server side. The current situation prevents me from generating email HTML with legacy attributes like "align" "bgcolor". |
On the server side, you can use very dirty string replacement based workaround. Use data-fokfokfok prefix, and it will be safe enough. Still, React should and has to allow custom attributes, because Polymer. @sebmarkbage ? |
So you would need to do a workaround for client side and another one for server side. Not very neat... :( Too bad that |
We want to move to a model where we render all attributes that you provide. Without a whitelist. There are a few concerns though. It's a bit dangerous because we might need to change the meaning and signature of those attributes. E.g. as complex properties gets added to HTML, your code might break between versions. We prefer rich data types instead of strings. We also have the issue of patterns like We could probably do it for web-components but not HTML or we could commit to always supporting string values and try to find an upgrade path for existing code. |
But isn't this true in web anyway (i.e. when not using React)? IMO it's the expected behavior in the web that if HTML adds an attribute and I already use it, whether by accident or on purpose, something might break. Moreover it's not like attributes get added really often.
Since |
@gaearon Yes, but properties are riskier. You're less likely to rely on a property (unless you patch prototypes) than an attribute. We try to model them as properties when possible. |
I didn't follow this last comment @sebmarkbage, are you talking about more complex attribute values in custom elements, that can't be simply represented by strings? I'm not clear on how that would work, I'd have thought that all communication with the custom element needs to be done through the DOM, as strings? Rather than rendering all attributes without a whitelist, maybe just adding a separate |
For custom elements, we can only really support simple strings since we don't have any rich information about what they will be. For known HTML elements we can use rich data structures for The nested I think we can find a way to support all the things. My primary concern is the upgrade path. I have some ideas there. We could replace existing uses of |
@sebmarkbage You are definitely the authority on this, but to me it seems natural to otherwise simply add a dedicated prop for "setting attributes/properties with raw values on DOM nodes" (i.e. It's probably not a very nice idea at all applied to custom elements, but then again, making the default implementation for all DOM elements non-whitelisted is definitely not nice either IMHO, especially as it conflates two very different behaviors without any hint as to which one you'll get. Obviously, just custom elements could be "pass-through" and it kind of fits nicely with the fact that they too are uniquely named (apart from handful SVG nodes that conflict, unless they need their own namespace anyway?). Anyway, just rambling here. :) |
My rationale is that it is unlikely that a DOM property that accepts a string would have different behavior from the attribute. E.g. Except for the imperative quirks of what time they're mutated. Browsers have bugs or unintuitive behavior for when they update, and at which time you would want to invoke the setter. There's also internal state in the component that might update a property while leaving the attribute the same. The point is that even if we added the special behavior for |
Would it make sense for a recommended approach to be officially documented somewhere? This thread is quite baffling. |
I've found this approach to work best in most cases |
I think we’re ready to do it, but I don’t think anybody on the team has time right now. If somebody wants to contribute a big feature to React this is the opportunity 😄 |
I dug into this a while back: I'd be happy to see this through, but I'm chewing on a few other outstanding pull requests right now if someone would like to pick up the work. Otherwise I could circle back this once I close out those pull requests |
After research in #6459, #7311, #10229, #10397, this was fixed by #10385, #10470, #10495, #10564, and some follow up work to ensure correctness in #10536, #10543, #10559, #10588, #10594, #10595. Learn more about the new behavior in React 16: |
Thanks to @nhunzaker who did most of the work. :-) |
Hmmm, but I still need to allow custom attributes on regular dom elements. I used to be happy with this:
But in react 16 you no longer expose the As you write in the release notes:
Well, please do! :) I rely on a library which, in turn, relies on custom elements (web components). I have to provide layout for it. While I'm not happy that they chose this path of adding custom attributes to the elements, I feel like providing required markup should be accomplishable. So in short, is there still a way to tell react that certain attributes are okay? If not, shouldn't this issue be reopened? |
@everdimension what attributes are you having trouble with? Arbitrary custom attributes should work fine with React 16 by default, which is why this is closed. |
Ok, I found out what's going on. The current behavior is something like this:
A bit surprising for me, but perhaps intended. In the first case react also gives a warning: Warning: Received If this is intended, I'll update my code accordingly. So is it?... :) |
@everdimension same here, I was surprised that custom boolean attributes are not supported. <div layout="row">
<div flex hide-lg>First item in row</div>
<div flex show hide-md="{{hideBox}}">Second item in row</div>
</div> There are probably other legit use of custom "boolean" attributes. IMHO they should be supported by React. |
They are supported, it just explicitly asks you to pass This is because there is no sure way to tell how to apply a boolean attribute. In some cases it's applied by setting an empty value (for true) and removing it (for false). In other cases it expects This is why you need to explicitly specify them:
depending on how it should be used. |
@gaearon Would it make sense to simply treat the In those cases, the following would all be considered "true":
And the following would be considered "false":
I especially think with propTypes, FlowType, TypeScript, and others, attributes used as boolean flags are probably done so very explicitly. This is also true because it's a bit more cumbersome to check for |
Then this form works for you, doesn’t it? <div something="" /> I understand the shorthand form feels “nicer”: <div something /> But it might actually be confusing in the future. There are discussions in the JSX spec repo about changing the semantics to compile this to const className = 'foo';
const user = props.comment.author;
return <Comment className user /> So I wouldn’t recommend relying on the shorthand form anyway. It’s not changing anytime soon, but within a few years—maybe. |
Using <div something="" /> works for me. According to html spec it is semantically the same as using an empty attribute, the latter being an implicit way to give the value of an empty string. |
@everdimension @gaearon Indeed! That's the principal problem here. The possibility of a false-positive is definitely high in the case of We are, after all, specifically talking about boolean attributes, and the current implementation is not consistent with how boolean attributes should work.
I argue on the side of intention specifically. Obviously, setting These are truthy values: <div something />
<div something="" />
<div something="true" />
<div something="false" /> I think the big "issue" here would moreso just be that the following will result in an undesired "truthy" outcome: <MyComponent something={false} /> Because instead of rendering it as: <div /> It would be rendered as: <div something="false" />
OR
<div something="" /> Creating a sort of "false-positive", when the desired intent would be to prevent the The component example above is explicit, of course, but in practice it could be if (randomlySourcedBoolean) {
return <MyComponent something />;
} else {
return <MyComponent />;
} Which is not a very intuitive solution :P |
@Swivelgames if you do To remove a boolean attribute you can use <div something={null} />
// renders <div />
<div something="" />
// renders <div something /> Please refer to the previous issues on this topic for more context: Make on/off, yes/no boolean attributes work #10589 We understand what the HTML spec says about boolean attributes, and recognize the inconsistency. React is a higher-level abstraction where boolean values can sometimes represent enumerable attributes which have a boolean set of values ( |
This thread is getting really long and every message spams a lot of people. The feature has been implemented in React 16. If you have specific concerns or ideas about it please file a new focused issue. Thanks! |
Various frameworks uses custom attributes. React could allow to extend default data- and aria- prefixes. Something like this:
The text was updated successfully, but these errors were encountered: