Access other className on hover in emotion css - css

I use EmotionCSS. I want to get an access to other className while catching focus on another. For example I have a component like that:
<div className={styles.root}>
<input className={styles.input} ... />
<div/>
The style file looks like that:
import { css } from '#emotion/css';
export const styles = {
root: css`
border: 1px solid black;
`
input: css`
...
&:focus {
// Here I want to access 'root' className and change its colour. Is it possible?
}
`,
}

You can try to use the :has() pseudo-class on the root to change the focus styles in input tag.
import { css } from "#emotion/css";
export const styles = {
root: css`
border: 3px solid black;
&:has(input:focus) {
border-color: red;
}
`,
input: css`
font-size: 1.5rem;
&:focus {
text-transform: uppercase;
}
`
};
export default function App() {
return (
<div className="App">
<div className={styles.root}>
<input type="text" className={styles.input} />
</div>
</div>
);
}

Related

Why is this CSS selector taking precedence over more specific selector?

I have this in my React app:
<Nav>
<BasicBtn>Basic button</BasicBtn>
<MainBtn>Main button</MainBtn>
</Nav>
The font size for buttons is set globally:
// globals.css
button {
font-size: 24px;
}
What I want to do is to reduce BasicBtn's font size via the Nav component to 20px, meaning I want it to be smaller when wrapped inside Nav; however, I do NOT want to affect MainBtn, whose font size is set to 14px in its own module. What happens, instead, is that the font size set in Nav overrides the font size set in MainBtn, so MainBtn is 20px as well instead of 14px.
This is my Nav component:
// Nav.js
import styles from "./Nav.module.css"
const Nav = ( { children } ) => <nav className={ styles.Nav }>{ children }</nav>
export default Nav
// Nav.module.css
.Nav button {
font-size: 20px;
}
This is my BasicBtn component:
// BasicBtn.js
import styles from "./BasicBtn.module.css"
import cn from "classnames"
const BasicBtn = ( { children, extraStyles } ) => {
return <button className={ cn( styles.BasicBtn, extraStyles ) }>{ children }</button>
}
export default BasicBtn
// BasicBtn.module.css
.BasicBtn {
padding: 10px;
background: green;
color: white;
}
This is my MainBtn component:
// MainBtn.js
import styles from "./MainBtn.module.css"
import BasicBtn from "../BasicBtn"
const MainBtn = ( { children } ) => <BasicBtn extraStyles={ styles.MainBtn }>{ children }</BasicBtn>
export default MainBtn
// MainBtn.module.css
.MainBtn {
font-size: 14px;
}
This is the generated HTML:
<nav class="Nav_Nav__WC_B6">
<button class="BasicBtn_BasicBtn__q_G1X">Basic button</button>
<button class="BasicBtn_BasicBtn__q_G1X MainBtn_MainBtn__92Bu4">Main button</button>
</nav>
And these, in this order, are the CSS rules that I get when clicking on the generated MainBTN (copied from DevTools):
.Nav_Nav__WC_B6 button {
font-size: 20px;
}
.MainBtn_MainBtn__92Bu4 {
font-size: 14px;
}
.BasicBtn_BasicBtn__q_G1X {
padding: 10px;
background: green;
color: white;
}
Shouldn't the .MainBtn_MainBtn__92Bu4 selector take precedence over .Nav_Nav__WC_B6 button, seeing as it is more specific?

Is it bad to use Refs to change styles in react?

here is a code example where i use Ref's to change style
import React, {useRef, useState, useEffect} from 'react'
import S from "./collapsible.module.css"
import PropTypes from 'prop-types'
import { faMinus, faPlus } from '#fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
function Collapsible(props) {
let myRef = useRef(null);
let buttonRef = useRef(null);
let [ button, setButton] = useState(true)
let Show = () => {
if(button) {
setButton(false)
buttonRef.current.style.backgroundColor = "#555"
myRef.current.style.maxHeight = myRef.current.scrollHeight + "px";
} else {
setButton(true)
buttonRef.current.style.backgroundColor = "hsl(181, 100%, 11%)"
myRef.current.style.maxHeight = "0px";
}
}
return (
<div
className={S.body}
>
<button
className={S.collapsible}
onClick={Show}
ref={buttonRef}
> {props.label}
<div className={S.icon}>
{button? <FontAwesomeIcon icon={faPlus} />:
<FontAwesomeIcon icon={faMinus} />}
</div>
</button>
<div
className={S.content}
ref={myRef}
>
<h3>{props.body}</h3>
</div>
</div>
)
}
Collapsible.propTypes = {
label: PropTypes.string,
body: PropTypes.string,
}
Collapsible.defaultProps = {
label: '',
body: "",
}
export default Collapsible
css:
.collapsible {
display: flex;
background-color: hsl(181, 100%, 11%);
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
outline: none;
font-size: 15px;
border-radius: 3px;
/* margin-bottom: 3px; */
box-shadow: 0px 1px 5px 1px black;
margin-top:13px;
}
.icon{
color:white;
position:absolute;
right:50px;
text-align:right;
justify-content: flex-end;
}
.active, .collapsible:hover {
background-color: #555;
}
.content {
padding: 0 18px;
max-height: 0px;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
This is just replicating this in React:
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_collapsible_animate
I have read that using Refs is bad, especially when using it to change the DOM, but if I didn't change the style with the exact amount shown in "scrollHeight" then the transition would be a messed up speed.
If there is another method Is this still bad practice?
It's more common practice to use a state value to determine the style like this:
<button
className={S.collapsible}
onClick={Show}
style={{backgroundColor: button ? "#555" : "hsl(181, 100%, 11%)"}
>
{props.label}
<div className={S.icon}>
{button ? (
<FontAwesomeIcon icon={faPlus} />
) : (
<FontAwesomeIcon icon={faMinus} />
)}
</div>
</button>
Or have a conditional className for your styles:
<button
className={`${S.collapsible} ${
button ? S.buttonColor : S.anotherButtonColor
}`}
onClick={Show}
>
{props.label}
<div className={S.icon}>
{button ? (
<FontAwesomeIcon icon={faPlus} />
) : (
<FontAwesomeIcon icon={faMinus} />
)}
</div>
</button>
and add .buttonColor and .anotherButtonColor to your CSS Module file (collapsible.module.css).
.buttonColor {
background-color: #555;
}
.anotherButtonColor {
background-color: hsl(181, 100%, 11%);
}
For the maxHeight on myRef, I'd do something like:
<div className={S.content} ref={myRef}>
<div style={{ maxHeight: myRef.current.scrollHeight }}>
<h3>{props.body}</h3>
</div>
</div>

styled component doesn't work with hierachy selectors

I'm learning to use styled components,but it looks like when i target css classes in hierarchy,it doesn't seem to work.Here i'm using i would like to make apply some styles wheneve use hovers on navigations links.
Here is my navbar code :
import React from "react";
import { Nav, Navbar } from "react-bootstrap";
import Flag from "../common/Image";
import styled from "styled-components";
import NavLink from "../common/NavLink";
const imageURL = "/static/img/abc.png";
const Navigation = ({ className }) => {
return (
<Navbar className={className} collapseOnSelect expand="lg" variant="light">
<Navbar.Brand href="#home">
<Flag imageSource={imageURL} size={[80, 70]} />
</Navbar.Brand>
<NavLink linkName="A" URL={"#"} />
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<NavLink linkName="B" URL={"#a"} />
<NavLink linkName="C" URL={"#b"} />
<NavLink linkName="D" URL={"#b"} />
</Nav>
<Nav>
<NavLink linkName="Espace de discussion" URL={"#discussions"} />
<NavLink linkName="Contactez-nous" URL={"#contact"} />
<Nav.Link>
<i clasName="fas fa-envelope" />
</Nav.Link>
<Nav.Link>
<i className="fas fa-bell" />
</Nav.Link>
<Nav.Link>
<i className="fas fa-user-circle" />
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
);
};
export default styled(Navigation)`
background-color: white;
border-bottom: 1px solid #e4e8f0;
`;
And my NavLink component
import React from "react";
import styled from "styled-components";
import { Nav } from "react-bootstrap";
import PropTypes from "prop-types";
const NavLink = ({ linkName, URL, className }) => {
return (
<Nav.Link className={className} href={URL}>
{linkName}
</Nav.Link>
);
};
NavLink.PropTypes = {
linkName: PropTypes.string,
URL: PropTypes.string
};
export default styled(NavLink)`
cursor: pointer;
color: green;
transition: 0.4s linear;
padding: 10px;
&:hover {
color: white;
font-size: 90;
background-color: #2e384d;
border-radius: 10px;
}
.navbar-light .navbar-nav .nav-link &:hover {
color: white;
}
`;
I the bellow gif,the animation is for changind links styled is working for all the links,but the color is only changing to white for the A link.But the form other background,border are changing but not the link color.Here the behaviour:
When i use the following code : .navbar-light .navbar-nav .nav-link &:hover {
color: white;
} in a normal css file without using styled component i get the good the exptected behavior.For solving i tried to use sass way of doing in the definition of my styled component like this :
.navbar-light {
.navbar-nav {
.nav-link {
&:hover {
color: white;
}
}
}
}
But nothing changes.How can i do for making all links text become white with styled-compont definition?
Alright, because of how <Nav> is wrapping your <NavLink>, the nav-link className has a higher specificity than your styled component className (the NavLink component is applying the styled component className before "nav-link" and, as a result, doesn't override the Bootstrap CSS). For example, the className looks like: "sc-lhVmIH gcJAof nav-link", where the styled component className: "sc-lhVmIH gcJAof" is being overridden by the last applied className "nav-link". There are several solutions to fix this, as shown below.
Solutions
Simply add color: white !important; in the styled NavLink:
export default styled(NavLink)`
cursor: pointer;
color: green;
transition: 0.4s linear;
padding: 10px;
border-radius: 10px;
&:hover {
color: white !important;
font-size: 90;
background-color: #2e384d;
border-radius: 10px;
}
`;
In Navigation, where <NavBar className={className}>...</NavBar> accepts a styled component className, add the following css to override the Bootstrap CSS stylesheet:
export default styled(Navigation)`
background-color: white;
border-bottom: 1px solid #e4e8f0;
&.navbar-light {
& .navbar-nav {
& .nav-link:hover {
color: white;
}
}
}
`;
Import the Bootstrap less into a less file and override the nav-link:hover className.
CSS Specificity
Here's how the CSS specificity is being applied to the DOM:
Demos
Click here for a working demo.
Working codesandbox (contains solution #1 and #2 -- you'll only need to use one of them, not both):

Change styles of parent on hover only if children not focused - Styled components

I have a div component:
const Parent = styled.div`
&:not(${Input}:focus):hover {
border-color: blue;
}
`;
and child which is input
const Input = styled.input``;
As you can see, I dont want to change border-color on Parent, if Input is focused. However atm the :hover doesnt work at all. Looking for help, thanks!
You can leverage :focus-within to do that.
div {
padding: 1em;
margin: 2em;
display: inline-block;
border-width: 3px;
border-style: solid;
}
div:hover {
border-color: red;
}
div,
div:focus-within,
div:focus-within:hover {
border: 3px solid blue;
}
<div>
<input type="text">
</div>
I don't know how you can handle it with only selector css, but you can trick it with javascript.
Your styled-component :
const Input = styled.input``
const Parent = styled.div`
border: 1px solid blue;
:hover {
border-color: ${p => p.inputFocus ? "blue" : "yellow"};
}
`
and in your render you can handle a state focus of you input.
render :
state = {
inputFocus: false
}
setFocus = () => this.setState({inputFocus: true})
unsetFocus = () => this.setState({inputFocus: false})
render() {
const { inputFocus } = this.state
return (
<Container inputFocus={inputFocus}>
<Input
onBlur={this.unsetFocus}
onFocus={this.setFocus}
/>
</Container>
)
}

toggle css class for two buttons when either is clicked

import React, { Component } from 'react';
class Buttons extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="displayButtons">
<input className='button1' onClick={this.props.get_menu_items_api}
value="Categories" type="button" ref="button"></input>
<input className='button2' onClick={this.props.get_addons_items_api}
value="Add Ons" ref="button1" type="button"></input>
</div>
)
}
}
export default Buttons;
I have these two buttons in react class.Their css is given below. What I want to do is on whichever button I click on it should turn orange and other should turn white. Initially Categories button is orange and Addons button is white.
I tried calling a function onClick that changes its class but how will it change the class of other button also.
.button2 {
border: none;
padding: 11px 32px;
text-align: center;
text-decoration: none;
line-height: 14px;
font-family: Roboto-Regular;
font-size: 12px;
border-radius: 2px 0 0 2px;
display: inline-block;
float: left;
}
.button1 {
background-color:#F6A623;
color: white;
}
.button2 {
background-color:white;
color: black;
}
You can save the status of the component identifier of the orange button and change it with using onClick.
Component:
class App extends React.Component{
constructor(){
super();
this.state = {
orangeButtonId: null
}
this.setOrangeButton = this.setOrangeButton.bind(this);
}
setOrangeButton(id){
this.setState({orangeButtonId: id});
}
render(){
return(
<div>
<input className={this.state.orangeButtonId === 1? "button1 orange" : "button1"} onClick={() => this.setOrangeButton(1)} value="Categories" type="button" ref="button" />
<input className={this.state.orangeButtonId === 2? "button2 orange" : "button2"} onClick={() => this.setOrangeButton(2)}
value="Add Ons" ref="button1" type="button" />
</div>
)
}
}
And styles:
input[type="button"]{
background-color: white;
}
input[type="button"].orange{
background-color: orange;
}
Check the fiddle https://jsfiddle.net/69z2wepo/83389/.
it can easily achived by using the component inner state + classnames library:
class Buttons extends Component {
constructor(props) {
super(props);
this.onButtonClick = this.onButtonClick.bind(this);
this.state = {
selectedButton: 'categories'
}
}
onButtonClick(e) {
this.setState({
selectedButton: e.target.value
});
if (e.target.value === 'categories') {
this.props.get_menu_items_api();
} else {
this.props.get_addons_items_api();
}
}
render() {
return (
<div className="displayButtons">
<input className={classnames({'button': true, 'selected': this.state.selectedButton === 'categories'} onClick={onButtonClick}
value="Categories" type="button" ref="button"></input>
<input className={classnames({'button': true, 'selected': this.state.selectedButton === 'addons'})} onClick={onButtonClick}
value="Add Ons" ref="button1" type="button"></input>
</div>
)
}
}
You need to keep track of button state within your class. When onClick is called set your state.
onButton1Click() {
this.setState({button1Down: true});
}
Then in the render call you need to use this state to set the class names to apply to your buttons.
render() {
let button1ClassName = 'button1';
if (this.state.button1Down) {
button1ClassName += 'button-down';
}
return ...

Resources