All Projects โ†’ Shakeskeyboarde โ†’ tsstyled

Shakeskeyboarde / tsstyled

Licence: ISC license
A small, fast, and simple CSS-in-JS solution for React.

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
CSS
56736 projects
EJS
674 projects

Projects that are alternatives of or similar to tsstyled

Twin.macro
๐Ÿฆนโ€โ™‚๏ธ Twin blends the magic of Tailwind with the flexibility of css-in-js (emotion, styled-components, stitches and goober) at build time.
Stars: โœญ 5,137 (+9778.85%)
Mutual labels:  styled-components, emotion, css-in-js, emotionjs, goober
Styled System
โฌข Style props for rapid UI development
Stars: โœญ 7,126 (+13603.85%)
Mutual labels:  styled-components, styling, emotion, css-in-js, theming
Styled Tools
Useful interpolated functions for CSS-in-JS
Stars: โœญ 761 (+1363.46%)
Mutual labels:  styled-components, emotion, css-in-js, jss
Filbert Js
A lightweight(~1kb) css-in-js framework
Stars: โœญ 167 (+221.15%)
Mutual labels:  styled-components, styling, emotion, css-in-js
Goober
๐Ÿฅœ goober, a less than 1KB ๐ŸŽ‰ css-in-js alternative with a familiar API
Stars: โœญ 2,317 (+4355.77%)
Mutual labels:  styled-components, emotion, css-in-js, goober
jss-material-ui
A enhanced styling engine for material-ui
Stars: โœญ 15 (-71.15%)
Mutual labels:  styled-components, style, jss, styles
Horror
๐Ÿ˜ฑ React HTML elements with CSS-in-JS
Stars: โœญ 78 (+50%)
Mutual labels:  components, styled-components, emotion, css-in-js
Css In React
๐Ÿญ CSS in React - Learn the best CSS in JS frameworks by example
Stars: โœญ 101 (+94.23%)
Mutual labels:  styled-components, emotion, css-in-js, jss
Fela
State-Driven Styling in JavaScript
Stars: โœญ 2,097 (+3932.69%)
Mutual labels:  components, styling, css-in-js
Grid
This package has moved and renamed
Stars: โœญ 2,079 (+3898.08%)
Mutual labels:  styled-components, emotion, css-in-js
Layouts
Grab-and-go layouts for React
Stars: โœญ 202 (+288.46%)
Mutual labels:  styled-components, emotion, styles
lab-cli
Command line utilities and exporting module for Compositor Lab
Stars: โœญ 52 (+0%)
Mutual labels:  components, styled-components, emotion
React Next Boilerplate
๐Ÿš€ A basis for reducing the configuration of your projects with nextJS, best development practices and popular libraries in the developer community.
Stars: โœญ 129 (+148.08%)
Mutual labels:  styled-components, emotion, css-in-js
Styled Components Vs Emotion
a short doc comparing the popular CSS-in-JS libraries styled-components and emotion
Stars: โœญ 204 (+292.31%)
Mutual labels:  styled-components, emotion, css-in-js
Reactackle
Open-source components library built with React and Styled-Components.
Stars: โœญ 278 (+434.62%)
Mutual labels:  components, styled-components, css-in-js
Css In Js
Autocomplete React Native / JS Styles and converting plain CSS to JS styles
Stars: โœญ 192 (+269.23%)
Mutual labels:  styled-components, css-in-js, jss
Next Dark Mode
๐ŸŒ‘ Enable dark mode for Next.js apps
Stars: โœญ 133 (+155.77%)
Mutual labels:  styled-components, emotion, css-in-js
Styled Ppx
Typed styled components in Reason, OCaml and ReScript
Stars: โœญ 236 (+353.85%)
Mutual labels:  styled-components, emotion, css-in-js
Macro Components
Create flexible layout and composite UI components without the need to define arbitrary custom props
Stars: โœญ 485 (+832.69%)
Mutual labels:  components, styled-components, style
Design System
Priceline.com Design System
Stars: โœญ 604 (+1061.54%)
Mutual labels:  components, styled-components, css-in-js

tsstyled

A small, fast, and simple CSS-in-JS styled components solution for React, written in Typescript.

  • Small: Less than 4kb (minified and gzipped) and zero dependencies.
  • Fast: Similar to other styled component solutions (benchmarks included).
  • Simple: Minimal/Opinionated API creates a great developer experience.
  • Typed: Written in Typescript. Designed for Typescript.

homepage bundle size github stars npm version npm downloads build codecov



Goals

  • Small bundle size and zero dependencies
  • Simple and opinionated API, with high quality types.
  • Type-safe themes without declaration merging
  • Future-proof CSS support
  • Server side rendering
  • Compatibility
    • React >= 16.14.0
    • ES2017/ES8 (eg. recent versions of Chrome, Edge, Safari, and Firefox)
    • Webpack tree-shakable

There are also some things that are non-goals. They were considered, and then the choice was made to explicitly not include support for them.

  • No auto vendor prefixing
  • No object styles
  • No component polymorphism (eg. as property, withComponent method)
  • No "non-style" features (eg. .attrs() method)
  • No React Native support

Getting Started

Install the tsstyled package and its react peer dependency.

npm add tsstyled react
yarn add tsstyled react

Create the styled API. Usually this is done only once per package.

import { createStyled } from 'tsstyled';

const styled = createStyled();

Style any HTML element type by using the tag name. The styled component supports all of the same props (included refs, which are forwarded) that the HTML element supports. Styling basic HTML elements is what you should be doing most of the time.

const StyledComponent = styled('div')`
  color: black;
`;

Style any React component which accepts a className property. This comes with more tech debt than styling HTML elements, because you can't be sure how the style class is being applied inside the component. This should be done rarely and with careful consideration.

const StyledComponent = styled(Component)`
  color: black;
`;

Extend the styling of an already styled component. Just like you want to keep your CSS specificity as low as possible, you also want to avoid trying to "patch" an already styled component. Styles can be dynamic, which means applying overrides can quickly get complicated. This should be an absolute last resort.

const ReStyledComponent = styled(StyledComponent)`
  color: gray;
`;

Style properties

You can add extra properties to the styled component by setting the generic parameter of the template string. Generally, you should prefix style properties with $ to indicate that they are only used for styling. Any property name which starts with the $ character will not be passed through to the underlying HTML element as an attribute.

interface ComponentStyleProps {
  $font?: string;
}

const StyledComponent = styled('div')<ComponentStyleProps>`
  font-family: ${(props) => props.$font};
`;

Global styles

Use the styled.global utility to create global style components.

const GlobalStyle = styled.global`
  body,
  html {
    margin: 0;
    padding: 0;
  }
`;

You can add style properties to global styles too.

interface GlobalStyleProps {
  $font?: string;
}

const GlobalStyle = styled.global<GlobalStyleProps>`
  body,
  html {
    font-family: ${(props) => props.$font};
  }
`;

Defining keyframes and fonts

Defining keyframes or font-faces is the same as defining any other style. Since they are not scoped to any particular component, they should probably only be used in global styles. To prevent name collisions, use the included getId utility to generate CSS-safe unique names.

const openSansFont = getId('Open Sans');
const slideInAnimation = getId('slideIn');

const GlobalStyle = styled.global`
  @font-face {
    font-family: ${openSansFont};
    src: url('/fonts/OpenSans-Regular-webfont.woff') format('woff');
  }

  @keyframes ${slideInAnimation} {
    from {
      transform: translateX(0%);
    }

    to {
      transform: translateX(100%);
    }
  }
`;

const StyledComponent = styled('div')`
  font-family: ${openSansFont};
  animation-name: ${slideInAnimation};
`;

Theming

A theme factory is provided instead of a single built-in theme. This allows themes to be strongly typed without relying on Typescript declaration merging (which does not provide great type-safety).

Creating a theme

A theme is essentially a context which provides theme constants. The createReactTheme utility makes it easy to create that kind of context, returning a hook for theme access, and a provider for theme overriding.

const [useTheme, ThemeProvider] = createReactTheme({
  fgColor: 'black';
  bgColor: 'white';
});

Note: The createReactTheme helper is only for convenience. Any hook could potentially be used, including theme hooks from other libraries.

Using a theme

Pass the a hook (or any function) which returns a theme value to the createStyled function. The theme value will then be available as the second argument passed to any styled template string functional value.

const styled = createStyled(useTheme);

const ThemedComponent = styled('div')`
  color: ${(props, theme) => theme.fgColor};
  background-color: ${(props, theme) => theme.bgColor};
`;

Style syntax

Style syntax is CSS-like, and all CSS properties, selectors, and at-rules are supported. In addition, SCSS-like nesting is supported with parent selector references (&).

Styling self

To apply styles directly to the HTML element or component being styled, use CSS properties at the top-level of the tagged template (no surrounding block).

const StyledComponent = styled('div')`
  color: red;
`;

Top-level CSS properties will be wrapped in a dynamic styled class selector

._s7y13d {
  color: red;
}

Styling children

Use CSS rule blocks to style children of the styled component.

const StyledComponent = styled('div')`
  .child {
    color: blue;
  }
`;

The styled dynamic class will be automatically prepended to all selectors to make them "scoped".

._s7y13d .child {
  color: blue;
}

Styling other styled components

Every styled component (except global styles) can be used as a selector for that specific styled component.

const StyledComponentA = styled('div')`
  color: blue;
`;

const StyledComponentB = styled('div')`
  ${StyledComponentA} {
    background-color: yellow;
  }
`;

The styled component's toString() method returns a unique selector string (eg. ".tss_s7y13d") which matches that specific styled component.

._s7y13d .tss_s7y13d {
  color: red;
}

Nesting rules

Nest rule blocks to create more complex selectors.

const StyledComponent = styled('div')`
  .child {
    color: blue;

    .grandchild {
      color: green;
    }
  }
`;

Just like the styled dynamic class is prepended to top-level selectors, so too are parent selectors prepended to child selectors.

._s7y13d .child {
  color: blue;
}
._s7y13d .child .grandchild {
  color: green;
}

Using parent selector references

Parent selector references (&) work the same way they do in SCSS/SASS. The one extra detail is that when a parent selector is used at the style root (not nested inside a parent block), it refers to the unique style class of the current style, which is the implicit/virtual parent block selector for the style.

const StyledComponent = styled('div')`
  && {
    color: red;
  }
  &:hover {
    color: blue;
  }
  .parent & {
    color: green;
  }
`;

Using at-rules

All CSS at-rules are supported (except @charset which isn't allowed inside <style> elements).

const StyledComponent = styled('div')`
  @media screen and (min-width: 900px) {
    color: red;
  }
  .child {
    @media screen and (min-width: 600px) {
      .grandchild {
        color: blue;
        .adopted & {
          color: green;
        }
      }
    }
  }
`;

At-rules will be hoisted as necessary, and parent selectors will be handled the same way they would be without the intervening at-rule.

@media screen and (min-width: 900px) {
  ._s7y13d {
    color: red;
  }
}
@media screen and (min-width: 600px) {
  ._s7y13d .child .grandchild {
    color: blue;
  }
  .adopted ._s7y13d .child .grandchild {
    color: green;
  }
}

Using empty values

If a CSS property value is "empty" (empty string, false, null or undefined), then the whole property will be omitted from the style.

const StyledComponent = styled('div')`
  color: ${null};
  background-color: red;
`;

The color property is not included because it has no value.

._s7y13d {
  background-color: red;
}

Commenting

Styles can contain both block (/* */) and line comments (//). Comments are never included in rendered stylesheets.

const StyledComponent = styled('div')`
  // This is a comment.
  /* And so...
     ...is this. */
`;

Style mixins (helpers)

The styled.mixin tagged template utility returns a mixin (AKA: helper) function. When the returned function is called, it returns a style string with all values interpolated.

Creating simple mixins

Mixins do not accept any parameters by default.

const fontMixin = styled.mixin`
  font-family: Arial, sans-serif;
  font-weight: 400;
  font-size: 1rem;
`;

const StyledComponent = styled('div')`
  color: red;
  ${fontMixin}
`;

Creating parametric mixins

Helpers which accept parameters can be created by setting the generic parameter of the styled.mixin template string.

interface FontMixinProps {
  scale?: number;
}

const fontMixin = styled.mixin<FontMixinProps>`
  font-family: Arial, sans-serif;
  font-weight: 400;
  font-size: ${(props) => props.scale || 1}rem;
`;

const StyledComponent = styled('div')`
  ${fontMixin({ scale: 2 })}
  color: red;
`;

Server Side Rendering (SSR)

During SSR, there is no DOM and therefore no document global. TSStyled detects this and uses a very minimal "virtual" DOM behind the scenes. So, after rendering the document body, use the renderStylesToString utility to get all of the <style> elements (generated by TSStyled components) as an HTML string.

const appHtml = renderToString(<App />);
const stylesHtml = renderStylesToString();
const html = `
<!doctype HTML>
<html>
<head>
  ${stylesHtml}
</head>
<body>
  <div id="root">${appHtml}</div>
</body>
</html>
`;

Testing

During testing, there may be a DOM (eg. jsdom) and a document global. However, the NODE_ENV environment variable should also be set to test (Jest sets this automatically). If it is, the SSR implementation is used. So, you can use the same renderStylesToString utility to test (eg. Jest snapshots) your styles.

expect(renderStylesToString()).toMatchSnapshot();

Comparison

TSStyled compared to other styled component solutions.

  • ๐ŸŸข Supported
  • ๐ŸŸก Partially supported
  • ๐Ÿ”ด Not supported
  • โญ• Not documented
Feature TSStyled Goober Styled Components Emotion
Library
Bundle size (approx. kB) 4 2 13 8
Zero dependencies ๐ŸŸข ๐ŸŸข ๐Ÿ”ด ๐Ÿ”ด
Typescript native ๐ŸŸข ๐ŸŸข ๐Ÿ”ด ๐ŸŸข
API
Tagged template styles ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
Object styles ๐Ÿ”ด ๐ŸŸข ๐ŸŸข ๐ŸŸข
Global styles ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
Polymorphism (as) ๐Ÿ”ด ๐ŸŸข ๐ŸŸข ๐ŸŸข
Property mapping (attrs) ๐Ÿ”ด ๐Ÿ”ด ๐ŸŸข ๐Ÿ”ด
Theming [1] ๐ŸŸข ๐ŸŸก ๐ŸŸก ๐ŸŸก
SSR ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
Style
CSS @media ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
CSS @keyframes ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
CSS @font-face ๐ŸŸข โญ• โญ• ๐ŸŸข
CSS @import ๐ŸŸข โญ• ๐Ÿ”ด ๐ŸŸข
Other CSS @ rules ๐ŸŸข โญ• โญ• โญ•
Vendor prefixing [2] ๐Ÿ”ด ๐ŸŸก ๐ŸŸข ๐ŸŸข
Rule nesting ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
Parent selectors (&) ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข
Style mixins [3] ๐ŸŸข ๐ŸŸก ๐ŸŸข ๐ŸŸข
Styled component selectors ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข

 

  • [1] Goober, Styled Components, and Emotion, all support only a single theme, which must be typed using declaration merging.
  • [2] Goober provides vendor prefixing as an additional package.
  • [3] Goober doesn't provide a css utility for creating mixins, but it does support function values in tagged templates.

Benchmarks

The benchmark app is available online, or by cloning the TSStyled repository and running the npm start command.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].