/styled-foundations

A foundation of primitive building blocks for rapid component design and development.

Primary LanguageTypeScriptMIT LicenseMIT


Styled Foundations

A foundation of primitive building blocks for rapid component design and development
Explore the docs »

Bug Report · Feature Request

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Roadmap
  5. Contributing
  6. License
  7. Acknowledgments

About The Project

There are many design systems packages available; however, I didn't find one that really suited all my needs or requirements so I've been building out my own. I wanted a small, simple yet extensible layer that work in conjunction with most css in js libraries that supported Typescript out of the box.

Features:

  • Hooks directly into your existing theme
  • Works with most css in js libraries, but built primarily to work along side styled-components
  • Responsive out of the box, each primitive and foundation can output different styles based on configured breakpoints
  • Existing foundations are set up to be unambiguous between the styles they produce
  • Rapidly create your own set of foundations or hook easily hook into the ones already provided

Of course, no one package will serve all projects since your needs may be different. I'll be enhancing and adding to this package as requirements arise. You may also suggest changes by forking this repo and creating a pull request or opening an issue.

(back to top)

Getting Started

Styled Foundations is a collection of utility functions that allow you to extend your React components in a easy and predictable manner, allowing you to use your already configured theme to control your styles without needing to refactor large parts of your codebase.

Prerequisites

Styled Foundations is to be used in conjunction with your css in js package of choice, if this is a new project you will need to install and configure one so Styled Foundations can be used.

Installation

To use Styled Foundations you'll need to install a css in js package such as styled-components, if you already have one installed you can skip that step and install just install styled-foundations.

yarn add styled-components
yarn add styled-foundations

Theming

Most css in js packages will provide you with some sort of ThemeProvider so you can access your projects theme when constructing your components. Styled Foundations will work out of the box with minimal additional configuration with your existing theme.

To make use of responsive foundations your theme will need to have a breakpoints property configured, this is how and where Styled Foundations looks when creating media queries when outputting css. You have two flavours to choose from, either an array of breakpoints or an object with named breakpoints, both have their pros and cons.

Breakpoint Array

// theme declaration that will be consumed by your css in js library
const theme = {
  breakpoints: ['48em', '64em', '76em', '88em'],
}

// prop usage when calling upon your components (these reflect the order declared in your theme)
;<Block margin={['0.25rem', '0.5rem', '0.75rem', '1rem']} />

Breakpoint Object

A key advantage of using an object over an array is that when providing the props for your components you can easily skip over the breakpoint by not including it. You can also use the array syntax in the props as long as you have each desired value in order.

// theme declaration that will be consumed by your css in js library
const theme = {
  breakpoints: {
    sm: '48em',
    md: '64em',
    lg: '76em',
    xl: '88em',
  }
}

// prop usage when calling upon your components (_ is the default size)
<Block margin={{ _: '0', sm: '0.25rem', md: '0.5rem', lg: '0.75rem', xl: '1rem' }} />

// or skipping some breakpoints
<Block margin={{ _: '0', sm: '0.25rem', xl: '1rem' }} />

(back to top)

Usage

Foundation

A foundation is the building block of Styled Foundations and is how you can easily construct reusable modifiers throughout your components. If there is a foundation that is not already provided by our existing set of foundations, you can create your own by using the foundation utility.

import type { Theme } from 'types'

import styled from 'styled-components'
import { foundation } from 'styled-foundations'

const color = foundation<Theme>({
  prop: ['color', 'colour'],
  properties: {
    color: {
      theme: 'colors',
      fallback: '#00DC82',
    },
  },
})

const ColoredParagraph = styled.p`
  ${color}
`

export default ColoredParagraph

The color foundation created here will allow you to provide either a color or colour prop to specify what text color the paragraph tag will be. It will look in your theme too and pickup and values under the colors property. If no color property is set on the ColoredParagraph component it will fallback and use #00DC82 as a default value.

  • prop either a string or an array of the names of the props to be used on the component
  • properties a object of css properties to be used in the returned styles
  • properties.theme a string with the key or path to an object of key value pairs in your theme
  • properties.fallback a string of the value which should be used if a value isn't found or provided

Shorthand Foundation

If your foundation does not need to use your theme, or have any fallbacks you can easily omit that by using a shorthand declaration of the foundation utility.

const paddingY = foundation({
  prop: 'py',
  properties: {
    paddingTop: true,
    paddingBottom: true,
  },
})

Multiple Foundations

If you're finding you are needing to group multiple foundations into a single object so you can easily import it to be used in your components, you can do so with the following syntax. Each option here can then be accessed via your components.

const padding = foundation([
  {
    prop: 'px',
    properties: {
      paddingLeft: true,
      paddingRight: true,
    },
  },
  {
    prop: 'py',
    properties: {
      paddingTop: true,
      paddingBottom: true,
    },
  },
])

Prebuilt Foundations

There currently are a few already prebuilt foundations you can use, I do plan to extend upon these! Here are a few you can directly import into your projects. The props are all optional and support both longhand names and shorthand names.

name props theme type
color color, colour, bg, backgoundColor colors ColorProps
display display DisplayProps
flex flex, flexBasis, flexDirection, flexFlow, flexGrow, flexShrink, flexWrap, alignContent, alignItems, alignSelf, gridGap, justifyContent FlexProps
layout height, minHeight, maxHeight, width, minWidth, maxWidth, overflow, overflowX, overflowY, size space LayoutProps
margin margin, m, mt, marginTop, mr, marginRight, mb, marginBottom, ml, marginLeft space MarginProps
padding padding, p, pt, paddingTop, pr, paddingRight, pb, paddingBottom, pl, paddingLeft space PaddingProps
position position PositionProps
text align textAlign TextAlignProps
Example Usage
import type { MarginProps, PaddingProps } from 'styled-foundations'

import { margin, padding } from 'styled-foundations'

type BlockProps = MarginProps & PaddingProps

const Block = styled.div<BlockProps>`
  ${margin}
  ${padding}
`

// example component usage
<Block my="10px" px="5px" />

Variants

You can use variants to apply different styles based on props, this can be useful when you're wanting to support multiple looks of a single reusable component. You can use this inline inside the component itself, or use a reference like in the example below.

type Shape = 'square' | 'round' | 'pill'

const shape = variant<Shape>({
  prop: 'shape',
  variants: {
    square: {
      borderRadius: '0px',
    },
    round: {
      borderRadius: '10px',
    },
    pill: {
      borderRadius: '100px',
    },
  },
})

const Button = styled.button`
  ${shape}
`

// example component usage
<Button shape="round" />

Conditional

The conditional foundation is used to colocate all your toggleable props in a single area, where they are no longer sporadically defined across a complex component with all the odd formatting they induce. You simply define either the success styles (if the condition passes where it is true), or any failure styles that could otherwise occur.

type ButtonProps = {
  wide?: boolean
  disabled?: boolean
}


const conditionals = conditional({
  success: {
    wide: {
      width: '100%',
    },
    disabled: {
      opacity: 0.6,
    },
  },
  failure: {
    disabled: {
      opacity: 1
    }
  }
})

const Button = styled.button<ButtonProps>`
  ${conditionals}
`

// example component usage
<Button wide disabled />

(back to top)

Roadmap

  • add responsive foundation to hook into breakpoints to remove the need to write media queries.
  • add more prebuilt foundations
  • improve documentation
  • add unit tests

See the open issues for a full list of proposed features (and known issues).

(back to top)

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/amazing-feature)
  3. Commit your Changes (git commit -m 'feat: add some amazing feature')
  4. Push to the Branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

(back to top)

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Acknowledgments

This project was inspired by styled-systems, an existing package that seems to be abandoned. I've created this package to better support my needs and any community needs, where I plan to continually add them here as required.

(back to top)