I am trying out React-Jss from cssinjs.org/react.jss and this is what I've done upto now:
Installation:
npm install --save react-jss
I then tested this file where I added a Hover to the footer just to give this a test:
import React from 'react';
import injectSheet from 'react-jss';
const style = {
Footer: {
backgroundColor: '#000000',
},
'&:hover': {
backgroundColor: '#ff0000',
}
};
export class Footer extends React.Component {
render() {
return (
<Footer>This is the footer</Footer>
);
}
}
export default injectSheet(style);
When I hover over the Footer component I would expect the footer to turn red but nothing is happening.
I'm I missing something or is something wrong in the syntax?
There's a handful of reasons the code above isn't working. There's issues with your React code beyond the JSS syntax.
In regards to the JSS style declaration specifically, let's first make sure you understand what you're declaring in the style object. The properties of the style object (in your case Footer, are the class names that you want to define and as such should probably be all lowercase. The value of each of those properties is an object containing the CSS styles that you want applied by that class. If you want to define a hover styles for a given class then you would declare those styles inside of the class's style object like so:
const style = {
footer: {
backgroundColor: '#000000',
'&:hover': {
backgroundColor: '#ff0000',
}
}
};
I suspect you're attempting to follow the first code example under 'Usage' in the package's readme. Here's a working example that follows that approach.
import React from 'react'
import injectSheet from 'react-jss'
const style = {
footer: {
backgroundColor: '#000000',
'&:hover': {
backgroundColor: '#ff0000'
}
}
}
const Footer = ({sheet}) => (
<div className={sheet.classes.footer}>This is the footer</div>
)
export default injectSheet(style)(Footer)
Below is a working example that utilizes the advantages of ES6 in case you're interested.
import React, {PropTypes} from 'react';
import injectSheet from 'react-jss';
const style = {
footer: {
backgroundColor: '#000000',
'&:hover': {
backgroundColor: '#ff0000'
}
}
};
#injectSheet(style)
export default class Footer extends React.Component {
static propTypes = {
sheet: PropTypes.object.isRequired
}
render() {
const {sheet} = this.props
return (
<div className={sheet.classes.footer}>This is the footer</div>
);
}
}
Related
I am looking at #vanilla-extract/css for my styling in React app. The method style exports a className from the *.css.ts file but I require inline styling for Shadow DOM encapsulation.
I was checking #stitches/react it provides a way called createCss were a css is a named export of the method.
I don't see any similar methods in #vanilla-extract/css.
export const sprinkles = createSprinkles(
responsiveProperties,
colorProperties
);
export const appStyle = sprinkles({
display: 'flex',
paddingTop: 'small',
backgroundColor: 'red'
});
console.log(appStyle) // => gives obfuscated css classname `_1jbh1078`
UPDATE 1
Though the question remains valid, but I have moved forward with #stitches/react at this point. See my answer for #stitches/react way of doing things.
Looks like #vanilla-extract/css doesn't give a way to export CSS. But #stitches/css has done a good job with some caveats.
import * as React from 'react';
import ReactDOM from 'react-dom/client';
import { createStitches } from '#stitches/react';
const { styled, getCssText, css } = createStitches({
theme: {
colors: {
red: '#F00',
blue: 'blue'
}
}
});
const box = css({
background: '$red',
color: '$blue'
});
const element: HTMLElement = document.getElementById('root');
const shadowRoot = ReactDOM.createRoot(
element.attachShadow({ mode: 'open' })
);
shadowRoot.render(<><div className={box()}>App Colored</div><style>{getCssText()}</style></>);
The getCssText extracts all the style sheets from the config and puts it under <style /> tags - The issue here is stitches/react has no ways to tree shaking unwanted variables.
The <style> tag in the Shadow DOM should only be placed after all the css functions are consumed.
I defined a object useStyle and called it in the component SecondTest defined background color, is it possible to add hover in the object useStyle
const useStyle = {
backgroundColor: "red",
};
function SecondTest() {
return <div style={useStyle}>SecondTest go down</div>;
}
export default SecondTest;
You can use Radium React Library
import React from "react";
import Radium from "radium";
const style = {
color: "#000000",
":hover": {
color: "#ffffff"
}
};
const MyComponent = () => {
return <section style={style}>hello world</section>;
};
const MyStyledComponent = Radium(MyComponent);
export default function App() {
return (
<>
<MyStyledComponent />
</>
);
}
You can accomplish it with events like onMouseEnter & onMouseLeave if you wish to use javascript to solve your issue. Easier way to do it would be just to give an element className like
<section className='myClass'>hello world</section>
and then just to add desired properties in your .css file which you can import in your component or globally.
.myClass {
color: #000000;
}
.myClass:hover {
color: #ffffff;
}
It is not possible to add hover with in-line styles.
I defined class component for my form in React but I am getting an error when I want to style it.
In functional component I use const useStyles = theme => ({}) and const classes = useStyles(); to style functional component and it works.
Now I need to style class component and I defined constants where I put all my style code for the class component.
In class component element (ex. Box) I use style property like :
<Box style={nameOfTheContant}/>
and it works.
In my class component I need to implement media queries and I use Material UI breakpoints for that but when I add :
const classes = useStyles();
inside class component, it does not work.
My goal is to use media queries inside class component because I need to have special CSS style for mobile device. In functional component I use theme.breakpoints.down["sm"] but in class component it is not possible.
Here is the simplified code:
const useStyles = theme => ({
searchPanel: {
display: "flex",
justifyContent: "center",
backgroundColor:"red",
[theme.breakpoints.down("sm")]: {
backgroundColor:"green"
}}});
export default class SearchPanel extends Component {
render() {
const classes = useStyles();
return (
<h1 className={classes.searchPanel}>Text</h1>
)}}
you can use withStyles when styling class components:
// your typical imports here ...
import { withStyles } from "#material-ui/styles";
const styles = theme => ({
searchPanel: {
display: "flex",
justifyContent: "center",
backgroundColor:"red",
[theme.breakpoints.down("sm")]: {
backgroundColor:"green"
}
}
});
class SearchPanel extends Component {
render() {
const classes = useStyles();
return (<h1 className={classes.searchPanel}>Text</h1>));
}
}
export default withStyles(styles)(SearchPanel);
I’m using Draft.js for a project. I created a component that allows you to choose a font from a menu, then apply that font to the selected text in the Draft.js editor.
The way I need to do this:
Dynamically add a #font-face rule for the selected font that includes the font name and file location;
Create a new CSS class containing the font-family property that uses the font name from the #font-face rule that was added; and
Apply that new CSS class to the selection.
I’ve gotten everything but #2 figured out. For #2, I’m not finding any clear methods or tools to use that allow me to create new CSS classes in the global space. I’m reading a lot about css-in-js, but everything seems bloated or overly complex.
I’m formatting the #font-face rule and class like this:
const newClass = {
'#font-face': [
{
fontFamily: `${font.label} ${FONT_FAMILY_PREFIX}-A`,
src: `url(/fonts/${font.value}-TD-Space.woff)`,
fontWeight: 'normal',
fontStyle: 'normal',
}, {
fontFamily: `${font.label} ${FONT_FAMILY_PREFIX}-B`,
src: `url(/fonts/${font.value}-TD.woff)`,
fontWeight: 'normal',
fontStyle: 'normal',
},
],
[`.${font.value}`]: {
fontFamily: `${font.label} ${FONT_FAMILY_PREFIX}-A, ${font.label} ${FONT_FAMILY_PREFIX}-B`,
},
})
But I’m just not sure where to put it so it’s accessible across the app.
Does this require the help of some package or is there a simpler way I can manage it without?
The simplest way is probably to use React's Context feature (docs here)
Basically, you define a context like this:
// style-context.js
export const Styles = {
style1: {
fontFamily: '"Times New Roman", Times, serif',
fontSize: '12px'
},
style2: {
fontFamily: 'Arial, Helvetica, sans-serif',
fontSize: '16px'
},
};
export const StyleContext = React.createContext({
theme: styles.style1, // default value
changeTheme: (newTheme) => {}
}
);
Then, you wrap your App like this:
// App.js
import React, { Component } from 'react'
import { FontContext, styles } from './style-context'
class App extends Component {
constructor(props) {
super(props)
// Function to change the theme
this.chooseTheme = (newTheme) => {
this.setState({
theme: styles[newTheme]
})
}
// State includes the current theme and function to change it
this.state = {
theme: styles.style1,
chooseTheme: this.chooseTheme
}
}
render() {
return (
// Wrap with the context's Provider, and pass in the theme from
// the state. Those state values will be available from all
// children, no matter how deep.
<StyleContext.Provider value={this.state}>
<div className="App">
{/* components */}
</div>
</StyleContext.Provider>
);
}
}
There are two ways to use the context, then. First, you can reference it in any child component like this:
// SomeComponent.js
import React, { Component } from 'react'
import {StyleContext} from './style-context'
class SomeComponent extends Component {
render() {
return (
<div style={
this.context.theme
}>
{/* ... */}
</div>
)
}
}
SomeComponent.contextType = StyleContext
export default SomeComponent
Really simple. The other way to access it is like this, which is useful if you have multiple Contexts you're combining on a single Component:
// TestButton.js
import React, {Component} from 'react'
import {StyleContext} from './style-context'
class TestButton extends Component {
render() {
return (
<StyleContext.Consumer>
{
// The contents of the Consumer tag will receive the
// 'value' prop set at the Provider level, which is,
// in this case, the App state containing the current
// theme and function to change it
({theme, chooseTheme}) => (
<button onClick={() => {chooseTheme('style2')}} style={theme}>Change Font</button>
)
}
</StyleContext.Consumer>
)
}
}
export default TestButton
Doing that will mean you don't need to programmatically change the classes that different divs are given, nor need to generate CSS classes in the first place.
Also, one of my favorite tricks for assigning styles is to use Object.assign() to do so, like this:
...
<div style={Object.assign(
{ backgroundColor: 'red', fontSize: '16px' },
this.context.theme
)}>
...
That way, you can set default values, decoupling the Context from the Component, and allows the theme's style attributes to only override matching keys, combining the rest.
I'm using Radium to write inline css in React and i have the following error when i want to use "hover":
Uncaught TypeError: Cannot read property '_currentElement' of null
Did i do something wrong ?
import React from 'react';
import Radium from 'radium';
class Header extends React.Component {
render() {
var styles = {
base: {
backgroundColor: 'white',
':hover': {
backgroundColor: 'black'
}
},
anchor: {
color: 'black',
':hover': {
color: 'white',
}
}
}
return (
<div>
<div style={styles.base}>
<a style={styles.anchor}>Some text</a>
</div>
</div>
);
}
}
Header = Radium(Header);
export default Header;
In fact, if i didn't use styles.anchor, it worked. So i don't understand why it doesn't work with styles.anchor.
Another problem, when i try to add the prefix #Radium before the class Header extends React.Component, i got a compilation's error.
Thank you !
If you're using babel you have to install plugin-transform-decorators-legacy in order for the #Radium to work properly but it's currently deprecated and I doubt it will be coming back anytime soon so I would stick with wrapping your component export default Radium(Header).