Already styled-components
React UI components styled with ... styled-components. Depends on polished for color shades and on react-transition-group for Navbar transitions. Also contains some inline SVG from fontawesome.
Install
npm i already-styled-components styled-components
(assuming you already have installed react and react-dom)
Available components
- Grid components (Container, Row, Column) + Centered utility
- Button
- Navbar
- AnchorLink
- Fab
- ProgressBar
Also includes some minor smooth scrolling and animation utilities.
Components
1. Grid
A grid layout implemented with flexbox. The implementation is from Philip Walton's "solved by flexbox" repo. What he describes as Grid is a Row component here and a Grid Cell is a Column. In short, Container component is not really important just a div, only Row and Column are "special". Each Column must be inside a Row. The Columns are responsive by passing props similar to Bootstrap (xs, sm, md, ...) but work the other way around. For example when you specify the extra large (xl) prop this applies to all lower breakpoints. Except of extra small (xs) where it takes the whole row by default. If you don't pass a responsive prop all Columns take the same space inside a Row. See the Column prop table for more details.
Example (holy grail layout)
// A holy grail layout.import React from "react";import createGlobalStyle from "styled-components";import Container Row Column from "already-styled-components"; const GlobalStyle = createGlobalStyle` body { margin: 0; }`; <> <GlobalStyle /> <Container ="center"> <Row ="#eee" ="15vh"> <Column>Header</Column> </Row> <Row ="70vh"> <Column ="#ddd">Left sidebar</Column> <Column ="#bbb" ="50%"> Content </Column> <Column ="#aaa">Right sidebar</Column> </Row> <Row ="#999" ="15vh"> <Column>Footer</Column> </Row> </Container> </>;
i) Container props
✨ Be careful of overflows if you use the width property alongside the padding property (or border). You may want to use the border-box
value for the box-sizing property to avoid surprises.
name | extra info | type | default |
---|---|---|---|
fluid | width: 80% or 100% (fluid prop wins over width prop) |
bool | false |
w | width | string | "80%" |
h | height | string | null |
m | margin | string | "auto" |
p | padding | string | null |
ta | text-align | string | null |
c | color | string | null |
bc | background-color | string | null |
ii) Row props
name | extra info | type | default |
---|---|---|---|
gutters | Changes the margin for the Row component and the padding for the immediate child Column components. It's visible if you add a div with a background color inside the Column. |
bool | false |
gutterSize | The amount of margin for the Row and padding for the Column children | string | "1em" |
w | width | string | null |
h | height | string | null |
m | margin. If you set gutters={true} this prop will be ignored |
string | "0" |
p | padding | string | "0" |
c | color | string | null |
bc | background-color | string | null |
ai | align-items | string | null |
jc | justify-content | string | null |
ta | text-align | string | null |
iii) Column props
✨ The responsive props (xs, sm, md, lg, xl) when present alter the flex shorthand property of the Column. More specifically the third parameter which corresponds to the flex-basis
. For example if you pass only md="33%"
we have in the code:
const Column = styleddiv` .... flex: ; @media screen and (max-width: 992px) { flex: ; } .... @media screen and (max-width: 576px) { flex: ; } `
and the result is (see the following table for defaults):
const Column = styleddiv` .... flex: 1; @media screen and (max-width: 992px) { flex: 0 0 33%; } .... @media screen and (max-width: 576px) { flex: 0 0 100%; } `
You can pass in breakpoint props (xs, sm, ...) any value that is valid for width and height CSS properties. Meaning px
, em
, %
...
name | extra info | type | default |
---|---|---|---|
flex | true = display: flex , false = display: block |
bool | false |
xs | Screen width <= 576px. By default Columns take the whole Row in this breakpoint (xs="100%") | string | "100%" |
sm | Screen width <= 768px | string | null |
md | Screen width <= 992px | string | null |
lg | Screen width <= 1200px | string | null |
xl | Screen width > 1200px. By default Columns occupy equal space inside a Row (flex-basis: 1). | string | null |
h | height | string | null |
m | margin | string | null |
p | padding. If you use gutters on the parent Row component this property will be overridden | string | null |
alignSelf | align-self. as is reserved if you're wondering 😠 |
string | null |
ta | text-align | string | null |
c | color | string | null |
bc | background-color | string | null |
iv) Centered
A simple utility component that uses flexbox to center vertically and horizontally the content. By default has
height: 100%
.
Centered props
name | extra info | type | default |
---|---|---|---|
fd | flex-direction | string | "column" |
ai | align-items | string | "center" |
h | height | string | "100%" |
m | margin. | string | null |
p | padding | string | null |
ta | text-align | string | null |
c | color | string | null |
bc | background-color | string | null |
2. Button
A slightly round button that is similar to the Bootstrap 4 button. It calculates the
background-color
onhover
and adds anoutline
from thebc
prop you specify. If you want to extend it withstyled(Button)
, I suggest to use the bc prop to keep this functionality.
Example
import React from "react";import Button from "already-styled-components"; <div> <Button>Click me</Button> <Button ="black"> "Icon" button </Button> </div>;
Example (extending Button)
import React from "react";import styled from "styled-components";import Button from "already-styled-components"; const Center = styleddiv` display: flex; align-items: center; justify-content: center; height: 100vh;`;const OrangeButton = ` border-radius: 0px; background-color: orange; color: black;`;const PinkButton = ` border-radius: 0px; font-size: 24px;`; <Center> <OrangeButton>Not so good</OrangeButton> <PinkButton ="pink" ="black"> Better </PinkButton> </Center>;
Button props
name | extra info | type | default |
---|---|---|---|
transparent | Transparent background-color and no transitions. You can use it as an icon button |
bool | false |
c | color | string | "#FFF" |
bc | background-color | string | "#00AFB1" |
hc | hover color | string | null |
br | border-radius | string | "20px" |
ff | font-family | string | "inherit" |
fs | font-size | string | "20px" |
3. Navbar
A render props component that renders a sticky navigation bar with a mobile full screen menu. More specifically renders by default a DesktopList and a MobileList component. You can pass the links via the children prop. If you want more control and customization you can use the DesktopListEmpty or MobileListEmpty. The last two render only a button that open and closes the mobile menu. Obviously you can provide you own implementations, but I believe the empty lists can cover a lot of scenarios.
✨ Note: The Navbar component registers an IntersectionObserver if the fixed property is set to true. In order for it to work on Safari you need this polyfill. The easiest way is to include the following script before the browser parses your JavaScript (at the head of the document):
Examples
- Example 1, no customizations
- Example 2, extending the default DesktopList
- Example 3, extending the MobileListEmpty and adding custom content inside
- More examples using the DesktopListEmpty and MobileListEmpty components
Prop tables
Example 1 (without any customizations)
import React from "react";import styled from "styled-components";import Container Navbar from "already-styled-components"; const Brand = styleddiv` font-size: 36px; font-style: italic; color: white;`; <Container ="200vh" > <Navbar => <a ="/">Home</a> <a ="/About">About</a> <a ="/Contact">Contact</a> </Navbar> </Container>;
Navbar props
name | extra info | type | default |
---|---|---|---|
desktopList | A function that returns the desktop navbar (render prop) | function | props => <DesktopList {...props} /> |
mobileList | A function that returns the mobile navbar (render prop) | function | props => <MobileList {...props} /> |
brand | The brand name or logo positioned at the left. | A React element | null |
fixed | The desktop list is actually positioned sticky not fixed. When it's true it doesn't change the position property anymore but instead performs a height transition when the user scrolls down. I'll change the name in version 3 to make more sense. |
bool | true |
children | The links that the desktop/mobile lists will render | A React element or more | null |
c | color | string | "#FFF" |
bc | background-color | string | "#313131" |
hc | :hover color | string | "orangered" |
Example 2 (extending the default DesktopList)
In this example we change the colors of the DesktopList when we scroll down. That is, if the Navbar is "fixed top" which is the default behavior.
import React from "react";import styled from "styled-components";import Container Navbar DesktopList from "already-styled-components"; const Brand = styleddiv` font-size: 36px; font-style: italic; color: white;`; const WhiteWhenFixed = ` box-shadow: 0 0 3px 0 black; transition: all 0.3s ease-in-out !important; background-color: ; a, div { color: ; } path { fill: ; }`; <Container ="200vh" ="beige"> <Navbar = = > <a ="/">Home</a> <a ="/About">About</a> <a ="/Contact">Contact</a> </Navbar> </Container>;
3. i) DesktopList props
name | extra info | type | default |
---|---|---|---|
showMobile | A function that shows the mobile menu | function | null |
links | The children of the Navbar if any. | A React element or more | None, it's required |
brand | The brand name or logo positioned at the left of the desktop list. | A React element | null |
fixedTop | Is the Navbar "fixed top" now? | bool | false |
fixedBreakpoint | A ref used by the IntersectionObserver of the Navbar |
node | None, it's required |
mobileBreakpoint | A number that indicates the screen size in which we hide the desktop links and show the hamburger button that opens the mobile menu. | number | 980 |
timeout | The timeout prop of the CSSTransition. It specifies how long the Navbar will transition when it enters the "fixed top" state (the user scrolls down) and when leaves (the user scrolls at the top of the screen). | object | { enter: 150, exit: 150 } |
className | For extending with styled-components. | string | null |
c | color | string | "#FFF" |
bc | background-color | string | "#1D1D1D" |
hc | :hover color | string | "orangered" |
3. ii) MobileList props
name | extra info | type | default |
---|---|---|---|
links | The children of the Navbar, if any | A React element or more | None, it's required |
mobileMenuVisible | Is the mobile menu visible now? | bool | None, it's required |
hideMobile | A function that hides the mobile menu. | function | null |
timeout | The timeout prop of the CSSTransition. It specifies how long will animate the mobile list when enters and leaves the screen. | object | { enter: 300, exit: 150 } |
className | For extending with styled-components. | string | null |
c | color | string | "#FFF" |
bc | background-color | string | "#1D1D1D" |
hc | :hover color for the links | string | "orangered" |
Example 3 (using and extending the MobileListEmpty)
In this example we put our own content in the mobile list and change the enter transition from fade-in to slide-down. Check these examples for more ideas.
import React from "react";import Link from "react-router-dom";import styled from "styled-components";import Container Row Column Centered Navbar MobileListEmpty from "already-styled-components"; const MobileListContent = ` &.mobile-list-enter { transform: translateY(-100vh); } &.mobile-list-enter-active { transform: translateY(0); transition: transform 0.5s ease-out; } &.mobile-list-exit { transform: translateY(0); } &.mobile-list-exit-active { transform: translateY(-100vh); transition: transform 0.3s ease-out; }`;const MobileLink = ` font-size: 36px; text-decoration: none; color: white; :hover { color: #cca43b; }`; <Container ="200vh" > <Navbar ="white" ="#242F40" ="#CCA43B" = > <Link ="/">Home</Link> <Link ="/about">About</Link> <Link ="/contact">Contact</Link> </Navbar> <Row> <Column ="100vh"> <Centered ="pink" ="white"> <h1>Slide-down navbar</h1> </Centered> </Column> </Row> </Container>;
3. iii) DesktopListEmpty props
name | extra info | type | default |
---|---|---|---|
showMobile | A function that shows the mobile menu | function | null |
children | The children of the desktop list (the links). | node | null |
fixedTop | Is the desktop list "fixed top" now? | bool | false |
fixedBreakpoint | A ref used by the IntersectionObserver of the Navbar |
node | None, it's required |
mobileBreakpoint | A number that indicates the screen size in which we hide the desktop links and show the hamburger button that opens the mobile menu. | number | 980 |
timeout | The timeout prop of the CSSTransition. It specifies how long the desktop list will transition when it enters the "fixed top" state (the user scrolls down) and when leaves (the user scrolls at the top of the screen). | object | { enter: 150, exit: 150 } |
className | For extending with styled-components. | string | null |
c | color | string | "#FFF" |
bc | background-color | string | "#1D1D1D" |
hc | hover color of the hamburger icon. | string | "orangered" |
3. iv) MobileListEmpty props
name | extra info | type | default |
---|---|---|---|
children | The children of the mobile list (the links) | node | null |
mobileMenuVisible | Is the mobile menu visible now? | bool | None, it's required |
hideMobile | A function that hides the mobile menu. | function | null |
timeout | The timeout prop of the CSSTransition. It specifies how long will animate the mobile list when enters and leaves the screen. | object | { enter: 150, exit: 150 } |
className | For extending with styled-components. | string | null |
c | color | string | "#FFF" |
bc | background-color | string | "#1D1D1D" |
hc | hover color for the close mobile menu icon. | string | "orangered" |
More Examples using the DesktopListEmpty and MobileListEmpty
- Slide-down mobile full screen menu using MobileListEmpty
- Slide-left mobile full screen menu using MobileListEmpty
- Slide-right small mobile menu using MobileListEmpty
- Transparent desktop menu using DesktopList
- Single page app that closes the mobile menu on click
4. AnchorLink
A button that'll smooth scroll to the specified section on click. Similar to GitHub heading links in markdown. Under the hood, is basically a slightly different Button component with a
transparent
prop. You can also provide an offset prop (if you have a fixed/sticky navbar) or a callback (e.g close a modal or a menu after click).
Example
import React from "react";import styled from "styled-components";import AnchorLink from "already-styled-components"; const Navigation = stylednav` height: 74px; background-color: #1d1d1d; position: sticky; top: 0;`;const FirstSection = styleddiv` height: 50vh; color: white; background-color: #333;`;const SecondSection = styleddiv` height: 150vh; background-color: azure;`; <div> <Navigation /> <FirstSection ="first-section"> <AnchorLink ="first-section" ="white"> First section </AnchorLink> <p>Close :</p> </FirstSection> <SecondSection ="second-section"> <AnchorLink ="second-section" => Second section </AnchorLink> <p>Perfect!</p> </SecondSection> </div>;
AnchorLink props
name | extra info | type | default |
---|---|---|---|
scrollTo | It's the section id without the # character |
string | None, it's required |
offset | You can use it if you have a fixed navbar for example | number | 0 |
callback | A function that you want to execute after the click. |
function | null |
children | node | null | |
fs | The font size for the text and the width of the SVG | string | "20px" |
c | color. It's the text color | string | "#000" |
o | opacity | number | 1 |
5. Floating Action Button
A material floating action button that represents the primary action of the page. You can pass as child your own icon (it's empty by default). The default position is at the bottom right corner of the screen. It has a ripple effect on click and an optional pulse animation to draw the attention of the user.
fortawesome
Example with icons fromnpm i @fortawesome/react-fontawesome @fortawesome/free-regular-svg-icons @fortawesome/fontawesome-svg-core
import React from "react";import Fab from "already-styled-components";import FontAwesomeIcon from "@fortawesome/react-fontawesome";import faPaperPlane faStar from "@fortawesome/free-regular-svg-icons"; <div> <Fab ="send email" => <FontAwesomeIcon = /> </Fab> <Fab ="#20c7b6" ="50px" ="22px" ="20px" ="do more stuff" = > <FontAwesomeIcon = /> </Fab> </div>;
Fab props
name | extra info | type | default |
---|---|---|---|
ripple | bool | false | |
pulse | bool | true | |
c | color | string | "#FFF" |
bc | background-color | string | "crimson" |
fs | font-size | string | "30px" |
w | width | string | "80px" |
t | top | string | null |
r | right | string | "3%" |
b | bottom | string | "3%" |
l | left | string | null |
zi | z-index | number | 1 |
6. Progress Bar
A YouTube/Stack Overflow like progress bar, positioned at the top of the screen.
Example
import React from "react";import styled from "styled-components";import ProgressBar Button from "already-styled-components"; const Section = styledsection` min-height: 90vh; display: flex; align-items: center; justify-content: center;`; Component { ; thisstate = loading: true ; thistoggleProgressBar = thistoggleProgressBar; } { this; } { const loading = thisstate; return <div> <ProgressBar ="rebeccapurple" = /> <Section> <Button ="rebeccapurple" => loading ? "Stop" : "Start" the progress bar </Button> </Section> </div> ; }
ProgressBar props
name | extra info | type | default |
---|---|---|---|
visible | bool | true | |
bc | background-color | string | "orange" |
zi | z-index | number | 1 |
Extending styles
You may want to change something in a component that a prop doesn't cover (or just don't want to use props). For example the ProgressBar component is positioned fixed at the top of the screen. You may want to place it at the top of a section.
import React from "react";import styled from "styled-components";import ProgressBar from "already-styled-components"; const Section = styledsection` position: relative; /* important for the container */ min-height: 40vh; background-color: ; display: flex; align-items: center; justify-content: center;`;const CustomProgressBar = ` position: absolute; top: 100%;`; <div> <ProgressBar /> <Section ="beige"> <h2> The orange progress bar is at the default </h2> </Section> <Section ="azure"> <h2> The black is at the bottom of this section </h2> <CustomProgressBar ="black" /> </Section> </div>;
✨ Note for extending components with styled(Component): If we take the ProgressBar example above, the original ProgressBar has top: 0
. If you want to position it at the bottom of the section, you'll have to override the top
property with top: 100%
in order to work. For example, it won't work with bottom: 0
.