Styling for Portal has evolved over the years since I have been working on it. We started with vanilla CSS in index.css
files. That was initially a problem for us as the CSS files were becoming too big and we also wanted to be able to nest styles. We then moved to SCSS so that we could have nesting and styling variables. We also moved more towards component specific SCSS files, rather than an index file for the whole directory.
Here is an example of a small SCSS file for a component:
.header-table-wrapper { .select-info-text { color: $mid-gray; font-size: 0.9rem; } .header-table-actions { display: inline-block; width: 100%; padding: 10px 0; position: relative; min-height: 40px;
button { margin-bottom: 0 !important; vertical-align: bottom; margin-right: 5px; }
p { display: inline-block; font-size: 0.9rem; color: $dark-gray; margin-bottom: 0; } } }
As you can see we have the entire SCSS file wrapped by the .header-table-wrapper
selector. By adding this class to the component itself, it ensures that the button and p styling we have enclosed in it will only be applied to that component.But what happens if we forgot to enclose that button styling in the wrapper selector? Yep, we’d have some CSS leaking causing all the buttons in the application to have that styling, which is very likely what we don’t want. This has unfortunately tripped us up a few times in the past, resulting in very unfortunate styling in places we might not expect. We needed something new.
Local Scoping - This is the crux of our problem as described above. By default, CSS is applied globally.
Encapsulation - We’d be moving all the relevant information about a component into one file. This lowers the risk of forgetting to update a specific file that pertains to the component.
Portability - Similar to the point above, by having everything about a component in one file, it can easily be moved around.
Reusability - We could create shared styling ‘objects’ and reuse them in different components safely.
Dynamic Functionality - By rendering the CSS with our JS, we can easily incorporate props that might be passed in from parent components to dictate our styling.
Below is an example of a component using React-JSS.
import React from 'react'; import classnames from 'classnames'; import colors from 'constants/jssStyle/colors'; import { createUseStyles } from 'react-jss';const feedbackMessageTypes = Object.freeze({ SUCCESS: 'success', ERROR: 'error', });
const useStyles = createUseStyles(() => ({ message: { width: '500px', float: 'right', border: `1px solid ${colors.midGray}`, borderRadius: '4px', }, title: (props) => ({ backgroundColor: props.type === feedbackMessageTypes.SUCCESS ? colors.green : colors.red, color: colors.white, padding: '10px', fontSize: '16px', }), text: { padding: '10px', fontSize: '14px', }, }));
const FeedbackMessage = (props) => { const classes = useStyles({ type: props.type });
const { text, title, setText, setTitle } = props;
return ( <span className={classes.message}> <div className={classes.title}> {title} </div> <div className={classes.text}>{text}</div> </span> ); };
export default FeedbackMessage;
There are a few things I want to unpack here. First, let’s focus on the actual style declaration.const useStyles = createUseStyles(() => ({ message: { width: '500px', float: 'right', border: `1px solid ${colors.midGray}`, borderRadius: '4px', }, title: (props) => ({ backgroundColor: props.type === feedbackMessageTypes.SUCCESS ? colors.green : colors.red, color: colors.white, padding: '10px', fontSize: '16px', }), text: { padding: '10px', fontSize: '14px', }, }));
As you can see above, we’re defining 3 different classes: message, title, and text. We don’t need these class names to be unique, as react-JSS will handle that on render. All we need to do is define our styling as an object and pass it in as the createUseStyles function.You might also notice we have a few variables playing parts here. We’ve imported a standard colors utility file so that we can use the colors defined by the application.
We also are passing in props to determine the background color for our component. This allows the component to render it’s styling differently based on the props that we might pass in.
Once we get to actually defining the component, we see this line:
const classes = useStyles({ type: props.type });
This takes our styles that we’ve defined above and converts them to a hash of classes that we can apply to our component jsx.And then finally we actually write the component JSX:
return ( <span className={classes.message}> <div className={classes.title}> {title} </div> <div className={classes.text}>{text}</div> </span> );
All we have to do now is write the jsx and include the classes we’ve defined in the correct place. For a more detailed tutorial, I recommend the official JSS documentation.(Feature photo by Denise Johnson on Unsplash)
Posted by Leah Haas Sanborn