Add CSS for html selector based on React state? - css

I'd like to set overflow-y: hidden for the html selector (not an element) based on whether a React class component state variable is true. Is that possible?

If you mean you want to apply the overflow-y to the actual HTML tag then putting this code in the render worked for me
...
render() {
let html = document.querySelector('html');
this.state.test === "test" ? html.style.overflowY = "hidden" : html.style.overflowY = "visible";
return (
....
)
};

You can do
function MyComponent() {
// Set your state somehow
const [something, setSomething] = useState(initialState)
// Use it in your className`
return <div className={!!something && 'class-name'} />
}
If you have multiple class names to work with, a popular package is (aptly named) classnames. You might use it like so:
import cx from 'classnames'
function MyComponent() {
const [something, setSomething] = useState(initialState)
return <div className={cx({
'some-class' : something // if this is truthy, 'some-class' gets applie
})} />
}

Yes, It's possible. You can do this.
function App() {
const [visible, setVisible] = useState(false);
useEffect(() => {
const htmlSelector = document.querySelector("html");
htmlSelector.style.overflowY = visible ? "unset" : "hidden";
}, [visible]);
return (
<button onClick={() => setVisible(prevState => !prevState)}>
Toggle overflow
</button>
);
}
See the full example on CodeSandbox

You can use the style property to set inline CSS:
<div style={{ overflowY: hide ? 'hidden' : 'auto' }}>

Related

Using arbitrary runtime strings for Tailwind CSS class positioning

How can I specify a div's position from runtime data? Should I use some hook to set the className string? I find a lot of the time it's async issues that cause this kind of problem.
Anyway I was hoping someone could point me in the right direction, it's possible what I want to do isn't even supported by tailwind:
{timeRecord.clockedTimes.map((time, index) => {
let date = new Date(time.start);
let topOffset = getTopOffset(date).toFixed(4);
let stringOffset = `top-[${topOffset}%]`;
let className = "absolute " +stringOffset+" outline outline-red-400 w-1/2 left-1/2";
return (
<div className={className} >
{stringOffset}
</div>
)
})}
If I copy the text displayed inside the div by rendering the stringOffset from within the div and remove the composition of the className and just make it a static string with the runtime data copy and pasted it set's the right position.
Tailwind isn't built dynamically upon render. If you know what the value is before you compile you can include it or us something like cx to append a className, but you'll have to style in this case, you may need to play with the style prop a bit:
interface getTopOffsetProps {
timeDate: Date
}
const getTopOffset = ({ timeDate }: getTopOffsetProps) => {
return timeDate
}
interface ClockedTimes {
time: string
}
const ChildComponent = ({ time }: ClockedTimes) => {
const date = new Date(time)
const stringOffsetStyle = `${getTopOffset({ timeDate: date })}`
return (
<div className="absolute outline outline-red-400 w-1/2 left-1/2" style={{ top: stringOffsetStyle }}>
{stringOffset}
</div>
)
}
interface ParentComponentProps {
timeRecord: string[]
}
const ParentComponent = ({ timeRecord }: ParentComponentProps) => {
return (
<div>
{timeRecord.map((time, index) => {
<ChildComponent time={time} />
})
</div>
)
}

How can I avoid inline styles with React?

The code written below works correctly, but I was told to re-do the code in order to avoid inline styles.
export default class ProductDetail extends Component {
makeStyle(name, value) {
return {
backgroundColor: name === 'Color' ? value : "#1D1F22",
}
}
render() {
return (
<div className='sizesWrapper'>
{size.items.map(item => (
<div
key={item.value}
style={this.makeStyle(size.name, item.value)}
className="productSize"
>
{size.name !== 'Color' && item.value}
</div>
))}
</div>
)
}
}
how can I use CSS to change the backgroud-color of each iteration of item in items array instead of using:
style={this.makeStyle(size.name, item.value)}
You can create a CSS file and import it in your JS file. It will apply the CSS to your component

Add styling to expression in Object Literal in React

This is what I have:
const weight = "bold";
const someBool = true;
return (
{someBool &&
`This should be ${weight}.`
}
)
I need to add styling to the expression in the object literal. I tried this, but it is returning as This should be [object object]. on the UI:
`This should be ${<span fontWeight="bold">{weight}</span>}.`
How do I do this correctly?
Use a Fragment to group your plain text and element (span) without having a real wrapper element.
I use React.Fragment below because I don't think stackoverflow's babel parser can parse the "short syntax" (<> / </>), but you can also use that in your real application.
In the example below, I used the style prop as well to apply the bolding. Passing a fontWeight prop doesn't work out of the box, you'd need a custom element or something like styled-system.
function App() {
const weight = "bold";
const someBool = true;
return (
someBool && (
<React.Fragment>
This should be <span style={{ fontWeight: "bold" }}>{weight}</span>.
</React.Fragment>
)
);
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
function App() {
const weight = "bold";
const someBool = true;
const style = { fontWeight: "bold" };
return (
someBool && (
<>
This should be <span style={style}>{weight}</span>.
</>
)
)}
ReactDOM.render(<App />, document.getElementById('app'));
There are 4 ways to style your component. Please visit this for deep knowledge.
https://medium.com/technofunnel/4-ways-to-add-styles-to-react-component-37c2a2034e3e

Change parent component background on hover in reactJS

I have following React code
Code
What I would like is to when I hover my "E-commerce" picture App component background should change on "E-commerce" picture background.
So respectively and for other pictures.
I will be very grateful if you help me solve this problem.
Context, according to the React docs, should be used only for truly global state like current user or theme. Using context for components makes them less reusable.
updated code
Your component tree is App -> SolutionBox -> SolutionItem.
You want to "react" to an event in SolutionItem in App but there is SolutionBox inbetween them so you have to thread the event thru SolutionBox to App.
Step 1
Add a prop to SolutionItem called on OnHover, this will be a function call back that any parent component can use to react to changes.
function SolutionsSectionBoxItem({ solutionIMG, onHover }) {
let callOnHover = state => {
if (_.isFunction(onHover)) {
onHover(state);
}
};
return (
<div className="solutions-section-item-box">
<img
src={solutionIMG}
alt=""
onMouseEnter={() => {
callOnHover(true);
}}
onMouseLeave={() => {
callOnHover(false);
}}
className="solutions-section-item-img"
/>
</div>
);
}
Step 2
Add a prop to SolutionBoxItem called on BGChanged, this will again be a function call back that will be called when any solutionitem onhover happens. This function will take a menuName string and pass either the current menu name or default.
function SolutionsSectionBox({ onBGChanged }) {
let callBGChanged = menuName => {
if (_.isFunction(onBGChanged)) {
onBGChanged(menuName);
}
};
return (
<div className="solutions-section-box-box">
<SolutionItem
solutionIMG={Ecommerce}
onHover={state => {
callBGChanged(state === true ? "Ecommerce" : "default");
}}
/>
<SolutionItem
solutionIMG={SalesMarketing}
onHover={state => {
callBGChanged(state === true ? "SalesMarketing" : "default");
}}
/>
<SolutionItem
solutionIMG={Analytics}
onHover={state => {
callBGChanged(state === true ? "Analytics" : "default");
}}
/>
<SolutionItem
solutionIMG={Middleware}
onHover={state => {
callBGChanged(state === true ? "Middleware" : "default");
}}
/>
</div>
);
}
Step 3
In the App component listen for the changes. In here we now set state when ever the mouse enters or leaves a solution item. From here you have to change the background, you are using css to control the background url, this will be harder since you now need css class for each background type. You could use the bgImage state value to change the name of the extra css className like 'AppSalesMarketing', 'AppEcommerce', etc.
export default function App() {
const [bgImage, setbgImage] = useState(E);
const onBGChanged = menuName => {
setbgImage(menuName);
};
return (
<div className={`App ${bgImage === "default" ? "" : `App${bgImage}`}`}>
<SolutionBox onBGChanged={onBGChanged} />
</div>
);
}
In CSS
Leave the original App class but based on the bgImage value add an additional one using the name of the bgImage + App like below to cascade down the updated background-image value.
.AppEcommerce {
background-image: url(https://placekitten.com/600/600);
}
.AppSalesMarketing {
background-image: url(https://placekitten.com/500/800);
}
.AppAnalytics {
background-image: url(https://placekitten.com/800/500);
}
.AppMiddleware {
background-image: url(https://placekitten.com/700/700);
}
Extra
I added lodash to test that the incoming props are functions before I call them, it is good to do defensive programming because you never know who may use your component in the future.
let callBGChanged = menuName => {
if (_.isFunction(onBGChanged)) {
onBGChanged(menuName);
}
};
Two ways to solve the problem. One is passing down a function to update state, the other is to useContext. In this case it makes sense to use context because you are passing down a function through multiple components that do not care about the function.
First thing to do is make the background image dynamic in the div's style and use context:
// Put this outside the component
export const BackgroundContext = React.createContext(null);
// -- snip
const [backgroundImage, setBackgroundImage] = useState(Ecommerce);
const updateBackgroundImage = newImage => setBackgroundImage(newImage);
// -- snip
<BackgroundContext.Provider value={updateBackgroundImage}>
<div className="App" style={{ backgroundImage: `url(${backgroundImage})` }}>
{/* -- snip */}
</BackgroundContext.Provider>
Now in your SolutionsSectionBoxItem component you can import the background context:
import BackgroundContext from "../App";
Then using that context and react's mouseover api, update the selected background image:
const setBackgroundImage = useContext(BackgroundContext);
// -- snip
<img onMouseOver={() => setBackgroundImage(solutionIMG)} {/* -- snip -- */} />
You can read more here: https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down

using className in react

So what's the best pratice for using className in react. In specific multiple class names. I'm reading through the documentation and I don't really get a clear answer. I've seen things like:
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
but is there a way for me to do something like this?
import React from 'react';
import ReactDOM from 'react-dom';
import './css/landing.css';
import './css/w3.css';
class Home extends React.Component {
const homeClasses = 'bgimg-1 w3-display-container w3-opacity-min';
render() {
return (
<div className={homeClasses}>
<h1>SUP</h1>
</div>
);
}
}
ReactDOM.render(
<Home />,
document.getElementById('root')
);
or even just list then out in the class name section?
It depends what your component should/will do.
If your component is fairly static you will want to use a built in style like your first example:
const mystyle = {
width: '100%',
...
}
<div style={mystyle}>...</div>
However, there are better ways that allow your component to be more dynamic for re-use, for instance using a class method to generate the style from props passed to it, like in this render function:
render() {
// User's preference or Default Style:
const defaultStyle = {
width: this.props.style.width || '100%',
height: this.props.style.height || '100%',
}
//if this.props.className doesn't exist use mycssclass
const defaultClassName = this.props.className || 'mycssclass'
return (
<div className={defaultClassName} style={defaultStyle}>...</div> )
Following this logic you can use the ternary operator to change the css class name based on props. A common solution is use an isActive state property and use it to determine which class should be used.
render() {
const activeClassName = this.props.className + ' mycomponent-active'
return (
<div className={this.props.isActive ? activeClassName : this.props.className} style={ this.props.style }
</div>);
}
Another common, but complex way to set your component's style is to use a function that will return a given style object, and use it like the first example.
Ultimately, you should decided whether you would like your component to be styled by the designer/user or should look the same no matter where it is used... if it is styled by the designer, just expose the CSS class name from props to the component or define a default:
<div className={this.props.className || 'someclassName'}>...</div>
otherwise, use an example above.
Yes, you can do this! Take a look at the snippet below:
class Example extends React.Component {
cssClasses = 'demo demo2';
render() {
return (
<div className = { this.cssClasses }>
Hello World
</div>
);
}
}
ReactDOM.render( <Example/> , document.getElementById('app'));
.demo {
color: blue
}
.demo2 {
font-size: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'></div>
Your error was the definition of the homeClasses. You can't declare it like
const homeClasses = '...';
Because, on the way that you did, homeClasses is a property of your component. You should not use const. Just:
homeClasses = '...';
And you forgot to use the this reference, because the homeClasses is an attribute of your component.
<div className={this.homeClasses}>
<h1>SUP</h1>
</div>
Exists and one away for this problem. You can use and read this data from file (example data.json) where can use this data like props of that.

Resources