This is an example project for you to reference when setting up a new web app using React and/or Sass. Alternatively, you can follow the installation steps below on your own project.
This is to help engineers and designers setup style related tools, and follow a frontend convention for the project. This makes the project more maintainable in the future.
To use this project as a starting point for your React web app, simply clone this repo and run:
-
npm install -
npm start
To setup a new project yourself, follow these instructions:
1. Bootstrap your web project using create-react-app.
npx create-react-app my-appcd my-appnpm start
- Install Node Sass:
npm install node-sass --save - Now you can rename
src/App.csstosrc/App.scss - Update the import in
src/App.jsfrom:import './App.css';to:import './App.scss'; - Restart the server and you should see your styles being imported as Sass!
This will be the folder where all global style references and declarations will live. Eg: global variables, mixins, framework styles, etc.
- Create a
stylesfolder inside thesrcdirectory - Create an empty
index.scssfile inside the folder you just created. - Update the import in
src/index.jsfrom:import './index.css';to:import './styles/index.scss';- Note: You can now delete
src/index.css
- Note: You can now delete
- Create a
.envfolder at the root of your project and add this to the new file:SASS_PATH=node_modules:src/styles. This let's you use relative imports in your.scssfiles. - Restart the server
Whether it's via SMACCS, ITCSS, RSCSS, Atomic Design or something else, every new project should follow a consistent folder structure.
For this example, we've picked a mix of Atomic Design and ITCSS. Atomic for our component/page scoped styles, and ITCSS for our global styles.
ITCSS suggests a sane way to separate global styles based on specificity, reach, and explicitness. For more info on ITCSS, please read this. We're only going to be using 2 principles of ITCSS, settings, and generic since Atomic deals with the rest.
-
Create the
settingsfolder inside of oursrc/stylesdirectory. Thesettingsfolder contains fonts, colors definitions, mixins, etc. -
Create a
_variables.scsspartial that lives inside thesrc/settingsfolder. -
Create a
_mixins.scsspartial that lives inside thesrc/settingsfolder. ITCSS puts this in it's owntoolsfolder, however we're going to combine that with settings so we can import just 1 file when we're working at the component level.- Note: if you want to bring in your own font declarations, we recommend creating a
_fonts.scssfile in this folder, and declaring your font-family there. We also suggest creating a 'font-face' and serving it from the project rather than Google fonts when possible.
- Note: if you want to bring in your own font declarations, we recommend creating a
-
Create a
settings.scssinside thesrc/settingsfolder that imports the two files we just created above:@import './variables'; @import './mixins';
-
Update our
styles/index.scssfile to import the file we just created:@import 'settings/settings';
This is where we import reset and/or normalize styles, box-sizing definition, CSS frameworks etc. If you are using a framework, remember to include your reset/normalize styles BEFORE you import your framework.
For this project, we're going to install modern-normalize. This normalizes default browser styles, and sets the box-sizing to border-box .
- Run
npm install modern-normalize --save - Add this to the end of
styles/index.scss:.. @import '~modern-normalize/modern-normalize'; ..
- Note the use of
~before the package name, this will look for the path within thenode_modulesdirectory.
We've picked Bootstrap for this project, and since we're using React, we'll bring in React Bootstrap.
- Run
npm install react-bootstrap bootstrap --save - Add this to the end (after modern-normalize) of
styles/index.scss:.. @import '~bootstrap/scss/bootstrap'; ..
- Note: If you need to 'customize' the default Bootstrap theme, create a
_custom.scssfile inside thestyles/settingsfolder.
Follow these instruction to setup and create an atom, molecule, organism, template, or page. You can see a working example of each on src/pages/atomic-page.
Atomic Design's ideologies categorize styles via atoms, molecules, organisms, templates, and pages. For detailed info on what these categorizes really mean, please read this.
-
Create each category folder in the
srcdirectory (atoms,molecules,organisms,templates, andpages). -
Note: Depending on your needs 'templates' and 'pages' can be redundant. If this is the case, remove or do not add templates to your project.
We're going to create a Button atom that uses Bootstrap's button, but has custom styles.
-
Create a new file called
button.jsxinside thesrc/atomsdirectory.import React from 'react' import BootstrapButton from 'react-bootstrap/Button' export function Button(props) { return ( <BootstrapButton className="brand-button">{props.title}</BootstrapButton> ) }
-
Next replace the contents of
App.jsx(you can delete theApp.test.js,logo.svg, files too):import React, { Component } from 'react' import { Button } from './atoms/button' class App extends Component { render() { return <Button /> } } export default App
-
Go to
http://localhost:3000/and you should see your new button rendered on the page!
Now we're going to add component level styles to our new Button component.
-
Create a new file inside
atomscalledbutton.scss -
At the top of the
button.jsxfile, import the Sass file:import React, { Component } from 'react' import { Button } from './atoms/button' import './button.scss' ...
-
Open
button.scssand import the global variables and mixins:@import 'settings/settings';
-
Create an accented button inside
button.jsx:.. export function AccentButton(props) { return ( <BootstrapButton className="brand-button brand-button--accent"> {props.title} </BootstrapButton> ) }
-
Render our new
AccentButtoninApp.js:import React, { Component } from 'react' import { Button, AccentButton } from './atoms/button' class App extends Component { render() { return ( <> <Button title={'Button'} /> <AccentButton title={'Accent Button'} /> </> ) } } export default App
-
Start writing your styles for the
Buttoncomponent. We recommend following BEM when naming your classes. If you don't know what BEM is, please read this..brand-button { padding: 1rem; &--accent { // BEM 'Modifier' class background-color: $brand-accent; // Comes from 'styles/settings/settings.scss' border-color: $brand-accent; @include hover() { background-color: black; border-color: black; } } }
Note: we recommend keeping nesting to a max of 2 levels if possible. We also recommend using BEM classnames for all selectors where possible. Eg: prefer
.title--2 {}instead ofh2 {}. This keeps styles more maintainable and less specific.
We're now going to create an EmailSignup molecule that is made up of atoms.
-
Create a new file called
email-signup.jsxinside thesrc/moleculesdirectory.import React from 'react' export function EmailSignup(props) { return <div className="email-signup" /> }
-
Next import the necessary
atomsand add them to the markup.import React from 'react' import { EmailInput } from '../atoms/email-input' import { Button } from '../atoms/button' import './email-signup.scss' export function EmailSignup(props) { return ( <div className="email-signup"> <EmailInput placeholder={props.placeholder} className="email-signup__input" /> <Button title={props.title} className="email-signup__button" /> </div> ) }
Note: If the
moleculeneeds component specific styling createemail-signup.scssinsrc/moleculesand import it intoemail-signup.jsx.
You can now use Button and EmailSignup directly on any new page you create, but we are going go one step further and create a SignupSection.
-
Create a new file called
email-section.jsxinside thesrc/organismdirectory.import React from 'react' export function SignupSection(props) { return <div className="signup-section" /> }
-
Similar to creating a
moleculeyou will now import the necessarymoleculesoratoms.import React from 'react' import { EmailSignup } from '../molecules/email-signup' export function SignupSection(props) { return ( <div className="signup-section"> <h2>{props.headline}</h2> <p>{props.cta_copy}</p> <EmailSignup placeholder={props.placeholder} title={props.title} /> </div> ) }
-
Next we will add structure to our
moleculeby importingContainer,Row, andColfrombootstrap.import React from 'react' import { EmailSignup } from '../molecules/email-signup' import Container from 'react-bootstrap/Container' import Row from 'react-bootstrap/Row' import Col from 'react-bootstrap/Col' import './signup-section.scss' export function SignupSection(props) { return ( <div className="signup-section"> <Container> <Row> <Col xs={12} md={6} lg={6}> <h2>{props.headline}</h2> <p>{props.cta_copy}</p> </Col> <Col xs={12} md={6} lg={{ span: 5, offset: 1 }}> <EmailSignup placeholder={props.placeholder} title={props.title} /> </Col> </Row> </Container> </div> ) }
-
Now create and import
signup-section.scssjust like we did with the abovemolecule.@import 'settings/settings'; .signup-section { background: $dark-gray; color: #fff; padding: 7% 0; }