Dynamic CSS via prop using CSSModules with React component - javascript

I'm learning how to use css modules with react, below is a working example of a checkbox here's what it looks like (pure HTML + CSS fiddle) without react.
import React from 'react'
import CSSModules from 'react-css-modules'
import styles from './checkbox.css'
export function Checkbox (props) {
return <div styleName="checkbox--container">
<input styleName="checkbox" type="checkbox" {...props}/>
<span styleName="checkbox--styled"></span>
</div>
}
export default CSSModules(Checkbox, styles)
This is great and all, but let's say my client comes back and wants me to change the checkbox color. Fine, seems easy enough? That fiddle above shows that there is a couple of hex-codes (#479ccf) for border and within the SVG background image. Ideally I'd be able to pass along a react prop that allows you to do something like this <Checkbox color="#666333"/> and blam! However I can't find any documentation / way to get information from the component to the CSS file.
What does this mean?
I know what the react community is going to say, that particular set of CSS isn't ideal. It can be written in javascript within the component and from there you can set the inline styles of the pieces of the checkbox to the prop color. I'm pretty sure this is possible. Is this necessary? I'd have to refactor the ::after code, question about that.
I started on making the SVG functions.
function SVGDash (color) {
return `data:image/svg+xml;charset=US-ASCII,<svg%20xmlns%3D"http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg"%20viewBox%3D"0%200%2012%2012"%20enable-background%3D"new%200%200%2012%2012"><style%20type%3D"text%2Fcss">circle%2Cellipse%2Cline%2Cpath%2Cpolygon%2Cpolyline%2Crect%2Ctext%7Bfill%3A%23${color}%20%21important%3B%20%7D<%2Fstyle><path%20d%3D"M6%200"%2F><path%20d%3D"M.8%207C.3%207%200%206.7%200%206.2v-.4c0-.5.3-.8.8-.8h10.5c.4%200%20.7.3.7.8v.5c0%20.4-.3.7-.8.7H.8z"%2F><%2Fsvg>`
}
function SVGCheck (color) {
return `data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20enable-background%3D%22new%200%200%2024%2024%22%3E%3Cstyle%20type%3D%22text%2Fcss%22%3Ecircle%2Cellipse%2Cline%2Cpath%2Cpolygon%2Cpolyline%2Crect%2Ctext%7Bfill%3A%23${color}%20%21important%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M23.6%205L22%203.4c-.5-.4-1.2-.4-1.7%200L8.5%2015l-4.8-4.7c-.5-.4-1.2-.4-1.7%200L.3%2011.9c-.5.4-.5%201.2%200%201.6l7.3%207.1c.5.4%201.2.4%201.7%200l14.3-14c.5-.4.5-1.1%200-1.6z%22%2F%3E%3C%2Fsvg%3E`
}

You could create a different class composing the class you want to change the color:
.checkbox--styled-red {
composes: checkbox--styled;
background-image: url("data:image .... FF0000 ....");
}
And set it in the component when you get the matching props.color:
import React from 'react'
import CSSModules from 'react-css-modules'
import styles from './checkbox.css'
function getStyleNameForColor(color) {
colorToStyleName = {
red: 'checkbox--styled-red'
};
return colorToStyleName[color] || 'checkbox--styled';
}
export function Checkbox (props) {
return <div styleName="checkbox--container">
<input styleName="checkbox" type="checkbox" {...props}/>
<span styleName={getStyleNameForColor(props.color)}></span>
</div>
}
export default CSSModules(Checkbox, styles)
Better yet, use classnames instead of getStyleNameFor(color).

Related

ReactJS CSS style Strangely get carried over to other component

I've got this problem in ReactJS where if I Set a background color of a Body element in one page component, the color is still there when I route to other component which is not using that particular CSS.
So for example I have a welcome component which import a welcome.css that styles the background color of the body element. Then when I route to other component by clicking Link in navigation to let say contact-us component, the background color is still there on contact-us even thou contact-us does not import the welcome.css.
But in the first place if I never visit the welcome, and directly visit the contact-us, on a fresh tab, the coloring is obviously not there.
Code example:
welcome.css
body {
background-image: linear-gradient(310deg, #1b2753, #836538);
background-repeat: no-repeat;
}
Welcome.js
import React from 'react';
import { Link } from "react-router-dom";
import './assets/css/style/welcome.css';
function Welcome() {
return (
<>
<H1>Welcome !</H1>
<Link to="/contact-us">Contact Us</Link>
</>
);
}
export default Welcome;
ContactUs.js
import React from 'react';
function ContactUs() {
return (
<>
<H1>Contact Us</H1>
</>
);
}
export default ContactUs;
In react, css stylesheets are global, so it will apply that css everywhere in the toold wherever that selector is used.
To avoid that use Css modules or give unique names to every selectors.
in this case, its better to use CSS Modules.
Example: Make your component specific css with <name>.module.css and import in all required components, then use import styles from './Button.module.css'; and use ${style.<class-name>}

next js className haven't been set

I've just started playing with next js. so I want to use css as module and setup classname for nav, but in rendered DOM this classname doesn't exist. I can see generated styles by webpack in "head" tag, but I dont see classname on my nav tag.
import React from "react";
import styles from './NavigationContainer.module.scss';
type Props = {};
const NavigationContainer: React.FC<Props> = ({children}) => {
return <nav className={styles.mainNavigationContainer}>{children}</nav>
};
export default NavigationContainer;
In JS, we cannot use - as a variable name it is considered as a minus to do the math.
It is a good idea to rename the CSS selector to .mainNavigationContainer so that the Next Js can get the correct CSS styles.
The JS part will remain the same.
https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css

React Bootstrap custom checkbox without id?

I'm having a hard time understanding why this simple Bootstrap custom checkbox doesn't work. I'm using React, Bootstrap, and React-Boostrap.
import React from "react";
import ReactDOM from "react-dom";
import { Button, Form, FormCheck } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
function App() {
return (
<div className="p-3">
<FormCheck custom label="Checkbox">
</FormCheck>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Online Example
Adding id="test" to FormCheck seems to cause the checkbox to work, but is is possible to not have to use id? (The checkbox is used within the component of an object in my actual code, and it would be unnecessarily complicated to come up with a unique id for every checkbox)
Try this:
<FormCheck>
<FormCheck.Label>Allow us to contact you?
<FormCheck.Input isInvalid type={radio} />
</FormCheck.Label>
<Feedback type="invalid">Yo this is required</Feedback>
</FormCheck>
The basic idea is that you need to change the way it's rendered.
By default it has label and input on the same level, meaning that you have to bind them using id and for. And you want to put input inside of the label to bind it without id.
You might need some custom css as mentioned in this answer: https://stackoverflow.com/a/57901478/4536543
If you do want to use the React Bootstrap components you will have to use an ID to use the FormCheck component. This is as within the FormCheck component the ID is used to call useContext() so that the component can access the element through the DOM.
Source Code:
/** A HTML id attribute, necessary for proper form accessibility. */
id: PropTypes.string,
const { controlId } = useContext(FormContext);
const innerFormContext = useMemo(
() => ({
controlId: id || controlId,
custom,
}),
[controlId, custom, id],
);
Source
Ended up finding the solution here (Normal bootstrap 4)
<FormCheck custom>
<FormCheck.Label>
<FormCheck.Input type="checkbox" name="checkbox-name" />
<div className="custom-control-label"></div>
</FormCheck.Label>
</FormCheck>
It involves a bit of a work around, nesting labels with checkboxes. Bootstrap 4 custom buttons seem to have strange behaviour

How to extend ReactJS' Link component and show innerHtml

I looked at many sources on how to extend a React component by inheritance. The examples I found were always adding events and not manipulating the innerHtml. So, I could not find a simpler way to do this:
// React packages
import React from 'react';
import { Link } from 'react-router-dom';
export default class LinkX extends React.Component {
render() {
return (
<Link
className={this.props.className}
to={this.props.to}
replace={this.props.replace}
>
<span>{this.props.html}</span> // Wrap with span
</Link>
}
}
In my example, I want to add a <span> that surrounds the inner text of the link. So, I added a new property html that I put as the text of the Link instance.
Then, I use it this way:
<LinkX to={"/"} html="Home" />
I wonder if there is a way to get the innerHtml from the LinkX component, surround it with <span>, and put that inside the Link without using props. Then use it like this:
<LinkX to={"/"}>Home</LinkX>
I feel like you need to use children like this:
export default class LinkX extends React.Component {
render() {
return (
<Link
className={this.props.className}
to={this.props.to}
replace={this.props.replace}
>
<span>{this.props.children}</span> // Wrap with span
</Link>
}
}
Then you can use it like this
<LinkX><b>bold</b></LinkX>

Styling react-toolbox elements with className

I seem to be having some issues in regards to styling the components without using a theme. I just want to change a couple of colors without needing to create a new theme per element.
In this case, I just want to change the color of the bar to a brownish color and right now I have an input class as follows:
import style from './style.scss'
const TextInput = (props) => {
<Input className={style.textInput} {...props} />
}
And in my style.scss file:
.textInput {
.bar {
background-color: #663300;
}
}
Any help would be appreciated.
ClassName doesn't work like that.
You can't pass a Css style to a className, that is wrong.
Either pass the class names you want to apply as a string (in your case I guess it would be className="textInput bar") or you can create a className with classNames library (in any case the final result will be a string).
Just make sure you're styles are included in the page that the component is going to render and react will be smart enough to render the correct css class for each component.
As you can check in here ClassName is a string

Categories