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
Can't target root with a dynamic tag name #147
Comments
@jaydenseric interesting use case :) Maybe we can make an exception for component names defined within the scope of the current component. As for now you can wrap |
Another use case I encounter is to be able to set a |
I believe I'm having a similar issue. I'm attempting to use dynamic tag names in combination with import React from 'react'
import styles from './styles'
type Props = {
children: string,
Element: 'span' | 'p' | 'h1' | 'h2' | 'h3',
kind: 'smTitle' | 'xlTitle',
}
// class declaration is lost
const TextBroken = ({ children, Element, kind }: Props) => (
<Element className={kind}>
{children}
<style jsx>{styles}</style>
</Element>
)
// works, but requires a span wrapper
const TextWorking = ({ children, Element, kind }: Props) => (
<Element>
<span className={kind}>{children}</span>
<style jsx>{styles}</style>
</Element>
) |
Bumped into this issue almost immediately when trying to add a className to a I've tried the suggested workaround but in this case Any thoughts on merging #244? |
@simonsmith the problem with passing the parent scoped // descendant
// className meant to be any className i.e. not added on purpose to pass styled-jsx scoped styles
const Child = ({className, children}) => (
<div className={'hello ' + className}>{children}</div>
) // parent
const Parent = ({children}) => (
<div>
{children}
<Child>hello</Child> {/* didn't plan on passing any className */}
<style jsx>{`div { margin: 50px }`}</style> {/* since styled-jsx passes the className to Child the inner one will get the margin too */}
</div>
) To solve this issue maybe we could allow components selectors like <style jsx>{`Child { color: red }`}</style> which generates a unique className for that component, not sure if this would work either. Also not every 3rd party component is made to accept a |
@giuseppeg If the className is generated in the parent and passed to the
You may have to school me on how styled-jsx is operating behind the scenes. Regardless, any thoughts on how I work around the issue with the |
@simonsmith To style the <div>
<Link className="my-link">something</Link>
<style jsx>{`div > :global(.my-link) { color: red }`}</style>
</div> |
styled-jsx is pretty amazing, simple and powerful, except the lack of this super obvious functionality, that anyone would expect from css-in-js library, which is a show stopper. Do you guys have any plans to support styling custom-defined user components without using :global ? |
@arsen that's on my radar, probably the next most important feature to add! |
@giuseppeg What should I do if I can't wrap my component with a div/span class Button extends React.Component {
render() {
return (
<React.Fragment>
<style jsx={true}>{`.button { color: white; }`}</style>
<button className={`button ${this.props.className}`}>
{this.props.children}
</button>
</React.Fragment>
)
}
}
class CoolButton extends React.Component {
render() {
return (
<React.Fragment>
<style jsx={true}>{`.cool-button { border: 1px solid #808080; }`}</style>
<Button className={`cool-button ${this.props.className}`}>
{this.props.children}
</Button>
</React.Fragment>
)
}
} I just want to extend my component this way, but it is not working, please, suggest some other solution. |
@iamawebgeek this should work class Button extends React.Component {
render() {
return (
<button className={`button ${this.props.className}`}>
<style jsx>{`.button { color: white; }`}</style>
{this.props.children}
</button>
)
}
}
class CoolButton extends React.Component {
render() {
const scoped = resolveScopedStyles(
<scope>
<style jsx>{`.cool-button { border: 1px solid #808080; }`}</style>
</scope>
);
const classNames = [
scoped.className,
'cool-button',
this.props.className,
];
return (
<React.Fragment>
<Button className={classNames.join(' ')}>
{this.props.children}
</Button>
{scoped.styles}
</React.Fragment>
)
}
} |
@a-ignatov-parc Awesome, it worked, thanks. Is there any way to make it more simple like just wrapping everything in |
Well, you can modify initial function resolveScopedStyles(scope) {
return ({ children }) => {
children.props.className += ' ' + scope.props.className;
return (
<React.Fragment>
{children}
{scope.props.children}
</React.Fragment>
)
};
} And then use it as class CoolButton extends React.Component {
render() {
const Scoped = resolveScopedStyles(
<scope>
<style jsx>{`.cool-button { border: 1px solid #808080; }`}</style>
</scope>
);
return (
<Scoped>
<Button className={`cool-button ${this.props.className}`}>
{this.props.children}
</Button>
</Scoped>
);
}
} |
When the styles are static it is better to define then outside of the |
@giuseppeg I thought that const styles = (
<style jsx>{`
.foo { ... }
`}</style>
);
function Component() {
return (
<div>
{styles}
</div>
)
} Is same as function Component() {
return (
<div>
<style jsx>{`
.foo { ... }
`}</style>
</div>
)
} Am I wrong? 🤔 Or you talking about? const styles = css`
.foo { ... }
`;
function Component() {
return (
<div>
<style jsx>{styles}</style>
</div>
)
} |
@a-ignatov-parc sorry I made some confusion because I didn't look properly at the examples. Styles that reference variables defined within the scope of the render method are treated as dynamic. Eg. render() {
const color = 'red'
return <div>
{this.props.children}
<style jsx>{`div { border: 1px solid ${color}; }`}</style>
</div>
} If The following syntax is not supported I think: const styles = (
<style jsx>{`
.foo { ... }
`}</style>
);
function Component() {
return (
<div>
{styles}
</div>
)
} Wheras the one below ( const styles = css`
.foo { ... }
`;
function Component() {
return (
<div>
<style jsx>{styles}</style>
</div>
)
} Somebody needs to work on improving this last behavior #345 |
@giuseppeg thanks for clarification 👍 |
Any progress on this? :) |
How would you folks feel about adding support for a special <Heading className="root" styled-jsx>
{children}
<style jsx>{`
.root {
color: red;
}
`}</style>
</Heading> |
Maybe for base scenarios, we should prefix I think most of the developers are expecting such behavior. |
so you mean automatic detection (whitelisting) for the use case of the OP? |
I thought that we can prefix Also, this behavior can be changed in babel's plugin options. By default, I'd suggest to leave it disabled. What do you think @giuseppeg? |
can you show me an example? |
<Heading>
<style jsx>{`
.root {
color: red;
}
`}</style>
</Heading> Transforms to <Heading>
<JSXStyle id="xxx" />
</Heading> <Heading className="root">
<style jsx>{`
.root {
color: red;
}
`}</style>
</Heading> Transforms to <Heading className="xxx root">
<JSXStyle id="xxx" />
</Heading> But function MyComp({ classes }) {
return (
<Heading className={classes}>
<style jsx>{`
.root {
color: red;
}
`}</style>
</Heading>
);
} Should transform to function MyComp({ classes }) {
return (
<Heading className={classes}>
<JSXStyle id="xxx" />
</Heading>
);
} |
I think if |
I think that it makes sense to automatically scope (add the className) in the case reported by the OP. In any other case we should scope only when the user adds a prop like |
Any progress on this ? 😺 |
@twltwl hi, want to pick this up? I can offer guidance |
@giuseppeg Yes I could. Some pointers on where to start would be apprichiated :) |
@twltwl sure, first of all you should branch off const tag = path.get('name')
if (
name &&
name !== 'style' &&
name !== STYLE_COMPONENT &&
(
name.charAt(0) !== name.charAt(0).toUpperCase() ||
/*
Allows tags references:
const Heading = `h{props.level}`
return <Heading>hi</Heading>
*/
Object.values(path.scope.bindings).some(binding =>
binding.referencePaths.some(r => r === tag)
)
)
) { And then add some tests here: https://github.com/zeit/styled-jsx/blob/next/test/fixtures/attribute-generation-classname-rewriting.js Add some new components and then run |
fixed in #462 will ship with styled-jsx v3 |
You can't target a root element with a dynamic tag name, using
className
:The text was updated successfully, but these errors were encountered: