Styled Components: Style Parent if child has attribute - css

I have a Parent that has a deeply nested child which can get an attribute if selected.
How do I style the background-color of the parent, only if a deeply nested child has an attribute of 'selected'?
<Parent>
<Child>
<NestedChild selected>
This is what I have tried:
const Parent = styled.div`
&[selected] { // But this only styled the child, not the parent}
`;

The CSS way
There isn't one - CSS doesn't allow an element to affect styling of its parents, only that of its children or siblings.
The React purist way
Use the useContext hook along with createContext and a context Provider, or simply pass a callback down through all the nested levels.
The hacky-yet-simple React + vanilla JavaScript way
// set up some styles for `has-child-selected` class
// ...
const Parent = ({ ... }) => {
return <div className="parent">
...
</div>
}
const Child = ({ selected }) => {
const ref = useRef(null)
useEffect(() => {
ref.current.closest('.parent')
.classList[selected ? 'add' : 'remove']('has-child-selected')
}, [selected])
return <div ref={ref}>
...
</div>
}
Edit: I realized I didn't even mention Styled Components in this answer, but I don't think it would change very much. Perhaps someone with more knowledge of Styled Components would be able to enlighten.

I think you can do it with CSS only. So I remember at least. try this.
you can change any tag, and any attr
li:has(> a[href="https://css-tricks.com"]){
color:red;
}
Looks Like it doesn't work at this time. but check when you see this.
:D :D

Related

How to use components in different ways (React)

I want to use simple components in different way and different ui rendering
For example a dropdown rendering a list may have several ui according to the page or context (=> padding, margins, font size and other css properties might change)
should I:
implement it by overwriting in the parent component (target css properties of the child component and apply them my css needs - at cost that if change happens in the child component like change in classname or what might break the parent design)
Pass flags to the component to handle those design and at cost that each component handle the design of each parent
There are different approaches to this and everybody has his own preferences.
I usually solve this by supporting the className property. The class is accepted as a prop and applied to the root. So it is easy to change things like outer margins or the background-color. I usually discourage modifications of deeply nested elements.
Example:
import classnames from 'clsx';
import style from './button.module.scss';
export const Button = ({ content, onClick, className }) => {
return (
<div
className={classnames(style.buttonRoot, className)}
onClick={onClick}>
{content}
</div>
);
};
and if I want to modify it anywhere I can do it thus:
import { Button } from './Button';
import style from './productView.module.scss';
// ...
<Button content={'Show products'} className={style.showProdButton} onClick={showProd} />
and
.show-prod-button {
background-color: #562873;
margin-left: 32px;
}

Any way to use classes instead of inline styling in this scenario?

Let's say I have this simple ListItem component in React.
const ListItem = ({ width, children }) => <li style={{ width }}>{ children }</li>.
What I want to do is, instead of using inline styling, to add a class, something like <li className={ `list-item--${ width }` }>{ children }</li>, then, in Less, I want to style that class by "extracting" the width from the class, something like this.
.list-item--#{ className } {
#width: className;
width: ##width;
}
Since I am a total beginner in Less, I don't know if this can be achieved. Or is there another way we can do this?

How to style a component "from the outside" with scoped css

I'm using scoped CSS with https://github.com/gaoxiaoliangz/react-scoped-css and am trying to follow the following rules (besides others):
Scoped component CSS should only include styles that manipulate the "inside" of the component. E.g. manipulating padding, background-color etc. is fine whilst I try to stay away from manipulating stuff like margin, width, flex etc. from within the component CSS
Manipulating the "outside" of a component (margin, width, flex etc.) should only be done by "consuming" or parent components
This is rule is somewhat derived from some of the ideas behind BEM (and probably other CSS methodologies as well) and allows for a rather modular system where components can be used without "touching their outside" but letting the parent decide how their internal layouts etc. works.
Whilst this is all fine in theory, I don't really know how to best manipulate the "outside styles" of a component from the consuming code which is best shown with an example:
search-field.scoped.css (the component)
.input-field {
background: lightcoral;
}
search-field.tsx (the component)
import './search-field.scoped.css';
type SearchFieldProps = {
className: string;
};
export const SearchField = (props: SearchFieldProps) => {
return <input className={`input-field ${props.className}`} placeholder="Search text" />;
};
sidebar.scoped.css (the consumer)
.sidebar-search-field {
margin: 16px;
}
sidebar.tsx (the consumer)
import './sidebar.scoped.css';
// ...
export const Sidebar = () => {
return (
<SearchField className="sidebar-search-field" />
(/* ... */)
);
};
In the above example, the CSS from the class sidebar-search-field in sidebar.scoped.css is not applied because the class passed to SearchField is scoped to the Sidebar and the final selector .sidebar-search-field[data-sidebarhash] simply doesn't match as the input element of the SearchField (obviously) doesn't have the data attribute data-sidebarhash but data-searchfieldhash.
ATM, I tend to create wrapper elements in situations like this which works but is rather cumbersome & clutters the markdown unnecessarily:
// ...
export const Sidebar = () => {
return (
<div className="sidebar-search-field">
<SearchField />
</div>
(/* ... */)
);
};
Question
Is there any way to "style scoped CSS component from the outside"?
Ps.: I'm not sure if all the above also applies to scoped styles in Vue. If not, please let me know how it works there so that I can create a feature request in https://github.com/gaoxiaoliangz/react-scoped-css.

Add a class to the parent .wp-block element in gutenberg editor

When Gutenberg creates a class, it seems to be of the format
div.wp-block
div.editor-block-list__insertion-point
div.editor-block-list__block-edit
div.editor-block-contextual-toolbar
div
<your actual block html goes here>
I'd like to be able to add a class to that top div.wp-block element so I can properly style my block in the editor. The class is dynamically generated based on an attribute so I can't just use the block name class. Is there a clean way of doing this? I can hack it using javascript DOM, but it gets overwritten quickly enough.
https://wordpress.org/gutenberg/handbook/designers-developers/developers/filters/block-filters/#editor-blocklistblock
const { createHigherOrderComponent } = wp.compose
const withCustomClassName = createHigherOrderComponent((BlockListBlock) => {
return props => {
return <BlockListBlock { ...props } className={ 'my-custom-class' } />
}
}, 'withCustomClassName')
wp.hooks.addFilter('editor.BlockListBlock', 'my-plugin/with-custom-class-name', withCustomClassName)
You can add class in your block edit view by using className that is present in this.props, className will print class in following format wp-blocks-[block_name]
edit( { className } ) { // using destructing from JavaScript ES-6
return <div className={ className }></div>
}
Suggestion
Always try to look for manipulating DOM via React instead of manipulating DOM directly because React manages it's own state and issues can occur by manipulating DOM directly.

How to influence foreign CSS classes when just using styled components

I am using react-table and I would like to apply CSS rules to the class rt-td which is not accessible nor modifiable through what their API offers.
In CSS I would just overwrite the CSS class from within my stylesheet. But how do you that with styled components? I heard it's an anti pattern, but what else should I do?
Suppose the parent of the the component ReactTable exported by react-table is a simple div.
const Test = () => (
<div>
<ReactTable someProperty={someValue}/>
</div>
)
you can influence the style of the class rt-td inside ReactTable by 1) converting the parent of ReactTable into a styled-components and 2) injecting style to override rt-td into the CSS of the aforementioned parent.
const Parent = styled.div`
.rt-td {
/* your custom style goes here*/
}
`
const Test = () => (
<Parent>
<ReactTable someProperty={someValue}/>
</Parent>
)
Usually that does the trick. If the style definition for rt-td inside react-table still overrides your custom definition due to specificity, keep repeating the class name rt-td inside Parent (like this .rt-td.rt-td) until your custom style wins.

Resources