-
Notifications
You must be signed in to change notification settings - Fork 262
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
Passing style to child component without using global styles #273
Comments
So it seems if I do this:
It seems to work. Alternatively I can also do:
from the parent component's styles. What is the right thing to do here? |
I think the the modifier/variant styles should be applied to the
use:
|
@colinmeinke that doesn't really work well, because what if That's the use case where this becomes a real problem. |
That's the main point, we'd have to figure out a way to control styles from the parent because passing a prop (eg. As for now the best way to do this is to use <div className="root">
<Link />
<style jsx>{`
.root > :global(a) { font-size: 60px }
`}</style>
</div> |
I've found a better workaround for this issue. function HighlightedLink(props) {
const {
theme,
children,
...otherProps,
} = props;
/**
* `scope` element is needed to properly parse `style` element
* and it could be any DOM element you want.
*/
const scope = resolveScopedStyles((
<scope>
<style jsx>{`
.link {
background: ${theme.background};
}
`}</style>
</scope>
));
return (
<Link
{...otherProps}
className={scope.wrapClassNames('link')}
>
{children}
<scope.styles />
</Link>
);
}
function resolveScopedStyles(scope) {
return {
className: scope.props.className,
styles: () => scope.props.children,
wrapClassNames: (...classNames) => [scope.props.className, ...classNames].filter(Boolean).join(' '),
};
} |
@a-ignatov-parc it might add some runtime overhead but it is genius! :D |
Yeah. But usually you shouldn't use child combinator selectors. Child component's markup is its private area and may change at any time. |
Agreed, unfortunately that's the only way to style 3rd parties components that don't accept a className. By the way I've been thinking to implement automatic className propagation for components and support this syntax: <Link className="link">
{children}
<style jsx>{`
.link { background: ${theme.background} }
`}</style>
</Link> Although I like the explicitness of your solution since on can do anything with the |
Sounds good 👍
Sure 😉 |
True. But it's better to choose another component/lib than apply such implicit styling. No one likes magic that can break your UI. |
Added @a-ignatov-parc workaround to the docs: https://github.com/zeit/styled-jsx#styling-third-parties--child-components-from-the-parent |
My typed version declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace JSX {
interface IntrinsicElements {
scope: React.DetailedHTMLProps<
React.StyleHTMLAttributes<HTMLElement>,
HTMLElement
>;
}
}
}
export function resolveScopedStyles(scope: ReactElement) {
const className = scope.props.className as string;
return {
className,
styles: () => scope.props.children,
wrapClassNames: (...classNames: string[]) =>
[className, ...classNames].filter(Boolean).join(" "),
};
}
|
I've got a child component, let's call it
Link
.This is the code for that:
Now say that I import that component within another component, called
Header
The code for that is:
However, unless I use
<style jsx global>
, then unfortunately the style doesn't get passed to the child component.I think a related issue is #197, but I haven't seen any outcome or update on that issue since June.
Is there a solution to fixing this issue?
The text was updated successfully, but these errors were encountered: