I have an image where the CSS class on the image needs to be change dynamically. It is passed in dynamically from this object from the key "size":
export const decals = [
{ label: 'Nikola Tesla', img: `/images/decals/tesla.svg`, size: `decalMed` },
{ label: 'Tattoo Mom Heart', img: `/images/decals/ARF149.svg`, size: `decalSm`}
Into another component here:
import styles from ./Shirt.module.css';
<img key={decals[decal].label} src={decals[decal].img} alt={decals[decal].label} className={`${styles}.${decals[decal].size}`}/>
The className= is the issue. I've tried so many different ways to pass this class.
I've captured this (decals[decal].size) into a variable before passing to the image tag.
I've tried to use the style tag instead of className and created a variable to hold the class.
I've changed around the brackets. I've tried passing it into an outside div.
Nothing seems to work.
I'm wondering if anyone can clue a react newbie in. Thank you!
if I am not wrong, you trying to dynamically manage classes that are passing through to the image element.To do that, I recommend you to use "classnames"
https://www.npmjs.com/package/classnames
With this package, you can control classNames with variables in your component.
I will try explain usage with a little example.
Your style file like
.yourParentClass {
&.decalMedClass {
// your styles for this class
}
&.decalSmClass {
// your styles for this class
}
}
your component file like
import Style from '../style.scss'; // Your classes
var classNames = require('classnames/bind'); // classname package
const cx = classNames.bind(Style);
// your code
render() {
return (
<img className={
cx({
yourParentClass: true,
decalMedClass: this.state.sizeMed,
decalSmClass: !this.state.sizeMed,
})
}
/>
);
}
Basically, you telling that which class gonna be active.
Please do not stick with my example, there are good examples on the npm page.
Related
I'm trying to add style to an element in my return of a react component, but I want to achieve this without adding a class. My text editor auto fills a style option, but I believe the syntax is wrong, since when trying to add a function on an onClick event, its a little different when its in the return of a react element. For example, instead of
onClick=function()
its
onClick={() => {function()}}
I'm hoping that instead of style={"background-color: green;"} its a different syntax to actually allow style changes once it hits the dom.
In-line styles can be done, and here is a code example as you have not provided one.
for example, lets inline style an h1 tag
<h1 style={{background-color:'green', color:'white'}}>This is a tilte</h1>
more can be found here
additionally, I would not recommend inline styling as it's not industry-standard and can cause your code to become bloted.
Style tags in react can indeed contain a references to functions.
I am not fully sure if you are working with React component classes or component functions, but your syntax can besides as follows. Create a variable called customStyle which will contain a function that returns your required style object:
customStyle = () => { return { color: 'red' } };
You can then reference customStyle inside markup as follows:
<div style={this.customStyle()}>My Element</div>
idont know if i understood your question well, You can achieve what you want by making a style state, then mutate it whatever style you want with setState
const [style, setStyle] = useState({})
const App = () => {
return <div style={style}>
<button onClick={() => setStyle({color: 'red'})}>handler button </button>
</div>
}
I am working on a tailwind + storybook component library where the theme colors change based on the class that is given to the html element.
Since components will have different colors in different themes, it would be great to have a theme toggle control in each story.
To achieve that, I was wondering if there is a way to add and remove a class to the html of each story preview with a control?
In order to get conditional classes on React you can use build the string for the className prop of your component like this:
render() {
let className = 'menu';
if (this.props.isActive) {
className += ' menu-active';
}
return <span className={className}>Menu</span>
}
Although it is recommended using the classNames utility in order to simplify this process like this:
render () {
var btnClass = classNames({
btn: true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
return <button className={btnClass}>{this.props.label}</button>;
}
You can read more about this in the React docs or in the classNames docs.
i am wondering is there a way to dynamically import a css file into react.
say i have a css file named style-light.css and i have another named style-dark.css.
is there a way to use react state or some other method to dynamically import the css files into the component based on the current value of the state ?
eg
import "../style-light.css" // default import
export default function TestImport(){
const [switch, setSwitch] = useState("light");
if(switch === "dark"){
import "../style-dark.css" // adds the style-dark import below the light one to overwrite the light css.
}
return (
<div>
<button onClick={()=> setSwitch("dark")}> click to get dark css </button>
</div>
)
}
bascially something like that?
any insight will be helpful. thanks
Option 1
For that I would recommend that you use CSS variables and only one CSS file. You can change the values of your variables based on a class applied on your page body. For example:
variables.css
:root {
--textColor: black;
}
[class="dark-theme"] {
--textColor: white;
}
With javascript you can add or remove the class from your html document, like this
component.js
document.documentElement.classList.add('dark-theme')
document.documentElement.classList.remove('dark-theme')
On your components styles you can use the variables with var(--variable)
component.css
.my-component-class {
color: var(--textColor);
}
Option 2
Use some CSS-IN-JS library like styled-components or emotion, you can use a ThemeProvider to change our theme accordingly with some state in your application. See this example here: https://styled-components.com/docs/advanced#theming
For Gutenburg's "core/image" block, they have different alignment options, specifically two that expose "full" and "wide". When you click on either one of these options, you will see that the data attribute "data-align" is added to the block editor's wrapper component with a value of either "full" or "wide".
I'm trying to create a custom block that has a similar features as the above. But I'm having a hard time figuring out how to add that custom attribute to my component's block editor wrapper.
Some things that I've tried are:
Using the block filter editor.BlockListBlock but the most I could do with this with my own knowledge is adjust the props, and the className. Adding a data-align="full" just meant adding a prop called data-alignment here.
https://developer.wordpress.org/block-editor/developers/filters/block-filters/#editor-blocklistblock
I also tried doing this with jQuery. Even if this worked, I definitely didn't want to use it as a permanent solution, I just wanted to see if it would work. So I added an on('click') event to one of my buttons so that it would target the wrapper component and modify the node, but that didn't work either. Probably because the block element is a dynamic element, it couldn't even be selected.
This is the wrapper that I'm trying to add a custom attribute to,
<div id="block-388288fa-ff20-459e-bce7-543b94fd77c4" class="wp-block editor-block-list__block block-editor-block-list__block is-selected" data-type="cgb/block-ee-hero-slider" tabindex="0" aria-label="Block: Hero Slider">
I just ran into the same problem. I found two solutions.
With getEditWrapperProps()
If you define your block yourself through registerBlockType(), then you can use getEditWrapperProps to define the data-align attribute:
registerBlockType('my-fully-aligned-block', {
title: 'My Fully Aligned Block',
category: 'common',
icon: 'admin-appearance',
/**
* Sets alignment.
*
* #param attributes
* #returns {{'data-align': *}}
*/
getEditWrapperProps(attributes) {
return {
'data-align': 'full'
};
},
edit,
save: () => null
});
With the editor.BlockListBlock filter
If you want to change the alignment for an existing block, you can use the editor.BlockListBlock filter that you already tried. Instead of setting the className property, like in the example in the documentation, you can pass in wrapperProps, that is going to be merged with what is defined in getEditWrapperProps().
function FullAlign(BlockListBlock) {
return props => {
const { block } = props;
// Bail out if it’s not the block we want to target.
if ('cgb/block-ee-hero-slider' !== block.name) {
return <BlockListBlock {...props} />;
}
return (
<BlockListBlock {...props} wrapperProps={{ 'data-align': 'full' }} />
);
};
}
wp.hooks.addFilter(
'editor.BlockListBlock',
'cgb/block-ee-hero-slider',
FullAlign
);
I'm trying to iterate through a list/array/object of things: (I used coffeescript to keep it clear, jsfiddle of full JS here. but it's just a forEach)
pages = for page, each of #props.ids
$('#start').append("<div id='"+page+"' ></div>")
React.renderComponent page(title: each.title, text: each.text), $("#"+page)[0]
and append each of them, instead of replacing, leaving only the last item in the list.
Where the #start element is the starting container, and I want to populate it with multiple elements, but I need to give each their own container, otherwise they will all overwrite eachother, the default reactjs behaviour.
I'm wondering if there's a way to tell react to append instead of replacing the div.
I'd like to avoid using jquery if possible, and do it purely react-ly.
I though about giving the React.renderComponent page the initial list, and then iterate in the previously called template, however, then i'm facing a different problem, I have to return a reactjs element object, consisting of the whole list, which I really don't prefer.
I need for the initial call to create individual, independent react templates, appending eachother in a list, prefferably without any extra containers, or using jquery.
I think you're getting the concept wrong. React's renderComponent indeed renders a single component, somewhere. Doing this multiple times only re-renders the same component at that place (aka idempotent). There's no real "append" statement, at least not in the way you asked for.
Here's an example of what you're trying to achieve. Forgot about renderComponent in this. It's just to put the component somewhere.
/** #jsx React.DOM */
var pages = [{title: 'a', text: 'hello'}, {title: 'b', text: 'world'}];
var App = React.createClass({
render: function() {
return (
<div>
{
this.props.pages.map(function(page) {
return <div>Title: {page.title}. Text: {page.text}</div>;
})
}
</div>
);
}
});
React.renderComponent(<App pages={pages} />, whateverDOMNodeYouWantItToBeOn);
See what I did there? If I want multiple divs, I just create as many as I want to see. They represent the final look of your app, so making a same div be "appended" multiple times doesn't really make sense here.
Create a div with a class extradiv:
<div class="extradiv">
</div>
In CSS, Set It's display to none:
.extradiv {
display: none;
}
.extradiv * {
display: none;
}
In JS implement this function:
function GoodRender(thing, place) {
let extradiv = document.getElementsByClassName('extradiv')[0];
ReactDOM.render(thing, extradiv);
extradiv = document.getElementsByClassName('extradiv')[0];
place.innerHTML += extradiv.innerHTML;
}
Than you can use this in place of ReactDOM.render:
GoodRender(<Component>My Text</Component>, YourDOMObject)