React css layouting inner components - css

Imagine that I have such html code:
<header>
<div class="header__logo logo">
<img class="logo__img" ...>
<span class="logo__status"...>
</div>
</header>
Here
.logo - is class that has styles, special for logo component.
.header-logo - has styles positioning logo inside the header.
So in react inside header component I would like to have something like:
<header>
<Logo className="header__logo" />
<header/>
But I can't since react is not automaticly handle className property.
Here I see this options:
Create a div wrapper to the Logo component and add this class to wrapper. As for me it is not an elegant way because it produce a lot of unnecessary divs.
Add logic to the Logo component, that will handle className property and append all outer classes to the root div inside the component. This is also ugly, because I have to add this boilerplate logic each time I want to layout a component inside some other component.
What is the react approach for solving such problems?

Yes, you cannot provide className attribute to a react Component. If you want to provide custom class to the same component, you can provide the className as a prop to the component which is added as a className in the child component.
I believe u need to do something like this.
var Header = React.createClass({
render: function() {
return (
<header>
<Logo customClass="header__logo logo"/>
</header>
);
}
});
var Logo = React.createClass({
render: function() {
return (
<div className={this.props.customClass}>
<img className="logo__img" />
<span className="logo__status" ></span>
</div>
);
}
});
Let me know if this is what you wanted to know or something else.

Related

Tooltip on absolute element in React JS

I am using this library https://tvkhoa.github.io/testlib/ to make some nice tooltip in my React App.
I use that code in my own component which look like this
const Tooltip = ({className, children, text, placement = 'bottom', isDisabled = false}) => {
return (
<ReactTippyTooltip className={className} html={<span>{text}</span>}
theme="dark" position={placement} arrow={true} arrowSize="regular"
animation="shift" hideDelay={300}>
{children}
</ReactTippyTooltip>
);
};
On basic elements such as simple images or buttons, everything works fine. But in some cases, I need to have a tooltip on an absolute element. For example on an InfoButton which overlaps an image.
<div className="relative"> <!-- container -->
<img />
<Tooltip> <!-- tooltip container -->
<InfoButton className="absolute top-0 left-0">
</Tooltip>
</div>
But I noticed that the tooltip appears bellow the image, instead of bellow the InfoButton.
If I have a look with the devtool, I can see that my InfoButton is inside a div that represents ReactTippyTooltip, and that div is 0*0 and is positionned bellow the image in the DOM. This is because only its content (InfoButton) is absolute and positionned inside the image. It can be summarized by the following image
I put a className to ReactTippyTooltip as a workaround and I made it absolute as well. Like this my tooltip is at the right place, but I feel like there is something wrong with what I am my doing.
Has anyone encountered some issues with tooltip on absolute elements ?
Can I do some better code with the library I am using ?
Does it exist some react tooltip library that use reference of the element to display the tooltip ?

How to dynamically add css style to pseudo classes in React

I'm trying to build a React component that shows multiple images stored in a database, where below each thumbnail image there is a button linking to its dedicated page. Now, I would like each button to show the dominant color of the image as background on hover. I already have the colors stored in database (artwork.palette.DOMINANT), but struggles to pass the hex code to the React component.
The problem is, inline style cannot set properties of pseudo selectors like a:hover, and because the color is dynamically fetched with the artwork object, I can not set it in a global and static css. Is there a way to set component-scoped style in React? Presumably like <style scoped>...</style>.
Here is my code, I only kept the gist of it for simplicity's sake.
const ImageBox = ({ artwork }) => {
return (
<Fragment>
<div className="image">
<img src={artwork.resources.THUMBNAIL} alt={artwork.title} />
</div>
<div className="caption">
<span>By {artwork.artist}.</span>
</div>
<div className="button">
<a href="!#" style={{ color: artwork.palette.DOMINANT }}>
Details
</a>
</div>
</Fragment>
);
};
You could use JS to modify the global properties of CSS.
Declare properties in index.css or App.css and add your basic styles that will utilize these variables.
:root {
--color-surface: white;
}
button {
background: var(--color-surface);
}
Modify these properties using JS(onMouseEnter and onMouseLeave). i.e.
//onMouseEnter
document.documentElement.style.setProperty("--color-surface", "black");
//onMouseLeave
document.documentElement.style.setProperty("--color-surface", "white")
There a few references you can follow:
Blog and CodSandBox
Note: Not sure if it's a good practice(I haven't seen in projects I've worked on), I would recommend using CSS-in-JS or libraries such as styled component.
Thanks to #PramodMali, I found the CSS-in-JS approach as a elegant way to solve this problem. For anyone who stumbles upon the same struggle in the future, here's how I solved it with react-css:
import { createUseStyles } from "react-jss";
const useStyles = (dominantColor = "#fff") =>
createUseStyles({
toDetailPage: {
color: dominantColor,
"&:hover": {
color: "#000",
background: dominantColor,
}
}
});
After defining the style generator, use it to dynamically set classes in component:
const ImageBox = ({ artwork }) => {
const classes = useStyles(artwork.palette.dominant)();
return (
<Fragment>
<div className="image">
<img src={artwork.resources.THUMBNAIL} alt={artwork.title} />
</div>
<div className="caption">
<span>By {artwork.artist}.</span>
</div>
<div className="button">
<a href="!#" className={classes.toDetailPage}>
Details
</a>
</div>
</Fragment>
);
};
This will then generate dynamic classes on render, for instance detailsButton-0-2-7, which applies the properties passed to the generator function when defining classes.
I was looking for how to set styles dynamically. My main intention was to write a style for hover. Using state to track whether it is hovered or not is good but that will cost render for each update. So I thought How I can solve it with out any state change. I end up doing this and it works perfectly.
<a
target='_blank'
href="#"
onMouseOver={(e) => e.target.style.color = 'red'}
onMouseOut={(e) => e.target.style.color = ''}
>
This is my link
</a>

How to set color of existing css class, from props of a react component

I am trying to modify the styling (colors) of existing class from the videojs Library.
I found that we can modify from css file. But I need to modify from the colour we get from react props, which is dynamic each time.
So, we have a class called vjs-control-bar coming from the videojs library to which we need to apply a color property with the value coming from react-props for eg. this.props.color. How we can achieve this ?
<div data-vjs-player>
<video ref={node => (this.videoNode = node)} className="video-js" />
</div>
The vjs-control-bar class wasn't here as it is coming from the video-js library
The right approach here would be to use one of those CSSinJS libraries and add rules that target the DOM elements that are rendered by the VideoJS library you are using.
Another alternative is to simply render a <style></style> tag in the component where you render the <video> component using the dangerouslySetInnerHTML prop.
Here is an example of how this might work:
function InnerComponent() {
return <h1 class="title">Text Color</h1>;
}
function App(props) {
return (
<div className="App">
<style
dangerouslySetInnerHTML={{
__html: `
.title {
color: ${props.color};
}
`
}}
/>
<h1>Hello CodeSandbox</h1>
<InnerComponent />
</div>
);
}
Here is sandbox - https://codesandbox.io/embed/white-star-9o897

Add className attribute to dangerouslySetInnerHTML contents

How to specify className attribute for div which contains 'hello world':
<div dangerouslySetInnerHTML={{__html: '<div>hello world</div>'}} />
One way is to set is to outer div like so:
<div dangerouslySetInnerHTML={{__html: '<div>hello world</div>'}} className='class-name'/>
and then in css style the child:
.class-name div {
(css stuff here)
}
But I want to set className directly to the div with 'hello world'
EDIT: Adding class name to injected html does not solve the problem, for example:
let content = '<div class="class-name">hello world</div>'
<div dangerouslySetInnerHTML={{__html: content}}
does not work, because in case same content is used many times then CSS collisions occur (I am using style-loader with CSS modules on)
I came across this question after 2 years and I wanted to achieve the exact same results. I didn't find any accurate answers here but I came up with a solution thanks to #jash8506 due to the brilliant answer to this question.
We have to utilize two react hooks
useRef
useLayoutEffect
According to the documentation basically, useRef can be used to access the DOM elements in React and useLayoutEffect can be used to read layout from the DOM and synchronously re-render.
We can access the firstChildElement in the container div and add classes to it's classList
Here is how the completed code looks like
const containerRef = useRef();
useLayoutEffect(()=>{
if (containerRef.current){
containerRef.current.firstElementChild.classList.add('class-name');
}
});
return (
<div ref={elRef} dangerouslySetInnerHTML={{__html: '<div>hello world</div>'}} />
)
<div className="post-excerpt" dangerouslySetInnerHTML={{ __html: post.excerpt}}/>

Animating content children in Angular (2/4)

I have a component that uses the <ng-content> selector to pull in some content children.
<!-- label-expand component-->
<div>
<ng-content select="[appLabel]"></ng-content>
</div>
So when a component creates an instance of this label-expand component like this:
<label-expand>
<span appLabel>Some label</span>
</label-expand>
I would like to set up the label-expand component, when hovered on to play an animation of the content child with the appLabel directive where the text gets bigger.
#Component({
selector: 'label-expand',
//...,
animations: [trigger('expandLabelState', [
//This is the animation I would like to pass to the content child
])]
})
export class LabelExpandComponent {
#ContentChild(AppLabelDirective) appLabel: AppLabelDirective
}
How do I pass an animation defined with the angular animation metadata in the label-expand component to it's ng-content content child? Or is this a problem that should instead be solved with CSS?

Resources