already-styled-components
v3.1.1
Published
React UI components styled with styled-components.
Downloads
35
Maintainers
Readme
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
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;
}
`;
export default () => (
<>
<GlobalStyle />
<Container fluid ta="center">
<Row bc="#eee" h="15vh">
<Column>Header</Column>
</Row>
<Row h="70vh">
<Column bc="#ddd">Left sidebar</Column>
<Column bc="#bbb" lg="50%">
Content
</Column>
<Column bc="#aaa">Right sidebar</Column>
</Row>
<Row bc="#999" h="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 = styled.div`
....
flex: ${({ xl }) => (xl ? `0 0 ${xl}` : 1)};
@media screen and (max-width: 992px) {
flex: ${({ md }) => md && `0 0 ${md}`};
}
....
@media screen and (max-width: 576px) {
flex: ${({ xs }) => xs && `0 0 ${xs}`};
}
`
and the result is (see the following table for defaults):
const Column = styled.div`
....
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";
export default () => (
<div>
<Button>Click me</Button>
<Button transparent c="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 = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
`;
const OrangeButton = styled(Button)`
border-radius: 0px;
background-color: orange;
color: black;
`;
const PinkButton = styled(Button)`
border-radius: 0px;
font-size: 24px;
`;
export default () => (
<Center>
<OrangeButton>Not so good</OrangeButton>
<PinkButton bc="pink" c="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):
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
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 = styled.div`
font-size: 36px;
font-style: italic;
color: white;
`;
export default () => (
<Container h="200vh" fluid>
<Navbar brand={<Brand>Styled Components</Brand>}>
<a href="/">Home</a>
<a href="/About">About</a>
<a href="/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 = styled.div`
font-size: 36px;
font-style: italic;
color: white;
`;
const WhiteWhenFixed = styled(DesktopList)`
box-shadow: 0 0 3px 0 black;
transition: all 0.3s ease-in-out !important;
background-color: ${({ fixedTop }) => fixedTop && `white`};
a,
div {
color: ${({ fixedTop }) => fixedTop && `black`};
}
path {
fill: ${({ fixedTop }) => fixedTop && `black`};
}
`;
export default () => (
<Container fluid h="200vh" bc="beige">
<Navbar
brand={<Brand>Styled Components</Brand>}
desktopList={props => (
<WhiteWhenFixed {...props} suppressClassNameWarning />
)}
>
<a href="/">Home</a>
<a href="/About">About</a>
<a href="/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 = styled(MobileListEmpty)`
&.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 = styled(Link)`
font-size: 36px;
text-decoration: none;
color: white;
:hover {
color: #cca43b;
}
`;
export default () => (
<Container h="200vh" fluid>
<Navbar
c="white"
bc="#242F40"
hc="#CCA43B"
mobileList={props => (
<MobileListContent {...props} timeout={{ enter: 500, exit: 300 }}>
<Centered h="100%">
<h2>My mobile links!</h2>
<MobileLink to="/">Home</MobileLink>
<MobileLink to="/about">About</MobileLink>
<MobileLink to="/contact">Contact</MobileLink>
</Centered>
</MobileListContent>
)}
>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</Navbar>
<Row>
<Column h="100vh">
<Centered bc="pink" c="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 = styled.nav`
height: 74px;
background-color: #1d1d1d;
position: sticky;
top: 0;
`;
const FirstSection = styled.div`
height: 50vh;
color: white;
background-color: #333;
`;
const SecondSection = styled.div`
height: 150vh;
background-color: azure;
`;
export default () => (
<div>
<Navigation />
<FirstSection id="first-section">
<AnchorLink scrollTo="first-section" c="white">
First section
</AnchorLink>
<p>Close :(</p>
</FirstSection>
<SecondSection id="second-section">
<AnchorLink scrollTo="second-section" offset={74}>
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.
Example with icons from fortawesome
npm 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";
export default () => (
<div>
<Fab aria-label="send email" onClick={e => console.log("Email sent!")}>
<FontAwesomeIcon icon={faPaperPlane} />
</Fab>
<Fab
bc="#20c7b6"
w="50px"
fs="22px"
t="20px"
pulse
aria-label="do more stuff"
onClick={() => console.log("More stuff done!")}
>
<FontAwesomeIcon icon={faStar} />
</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 = styled.section`
min-height: 90vh;
display: flex;
align-items: center;
justify-content: center;
`;
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true
};
this.toggleProgressBar = this.toggleProgressBar.bind(this);
}
toggleProgressBar() {
this.setState({ loading: !this.state.loading });
}
render() {
const { loading } = this.state;
return (
<div>
<ProgressBar bc="rebeccapurple" visible={loading} />
<Section>
<Button bc="rebeccapurple" onClick={this.toggleProgressBar}>
{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 = styled.section`
position: relative; /* important for the container */
min-height: 40vh;
background-color: ${({ bc }) => bc};
display: flex;
align-items: center;
justify-content: center;
`;
const CustomProgressBar = styled(ProgressBar)`
position: absolute;
top: 100%;
`;
export default () => (
<div>
<ProgressBar />
<Section bc="beige">
<h2>
The orange progress bar is at the default position (fixed top of the
screen)
</h2>
</Section>
<Section bc="azure">
<h2>
The black one (CustomProgressBar) is at the bottom of this section.
</h2>
<CustomProgressBar bc="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
.