Skip to content

rognstadragnar/classnames-in-js

Repository files navigation

classnames-in-js

A more sane approach to CSS in React (and Preact)

When you love the idea of styled-components and CSS-in-JS, but you also kind of hate it.

Heavily inspired by how styled-components and emotion lets us write components, but without having to write CSS in JavaScript.

Usage

Installation

npm i classnames-in-js
gzip size module tag-api safeguards (?) theme context
~3kb classnames-in-js
~0.5kb classnames-in-js/lite
~3kb classnames-in-js/preact awaiting context api in Preact X
~0.4kb classnames-in-js/preact-lite

Basic usage

import React from 'react'
import ReactDOM from 'react-dom'
import { styled } from 'classnames-in-js'

const Heading = styled('h1', 'heading')

ReactDOM.render(<Heading>Hello</Heading>, document.body)

// <h1 class="heading">Hello</h1>

Integrates with CSS modules

import React from 'react'
import ReactDOM from 'react-dom'
import { styled } from 'classnames-in-js'
import styles from './styles.css'

const Heading = styled('h1', styles.heading)

ReactDOM.render(<Heading>Hello</Heading>, document.body)

// <h1 class="heading-lkjfos">Hello</h1>

Conditionally applying classes

If classnames-in-js recieves a function as the second argument it will be called with the component props and/or theme.

import React from 'react'
import ReactDOM from 'react-dom'
import { styled } from 'classnames-in-js'
import cx from 'classnames'

import styles from './styles.css'

const Heading = styled('h1', props =>
  cx({
    [styles.heading]: true,
    [styles.headingDark]: props.dark
  })
)

ReactDOM.render(<Heading dark>Hello</Heading>, document.body)

// <h1 class="heading-lkjfos heading--dark-lkjfos">Hello</h1>

Appending and overriding

If a consumer passes a className prop it will be appended.

import React from 'react'
import ReactDOM from 'react-dom'
import { styled } from 'classnames-in-js'

const Heading = styled('h1', 'heading')

ReactDOM.render(
  <Heading className="heading--dark">Hello</Heading>,
  document.body
)

// <h1 class="heading heading--dark">Hello</h1>
import React from 'react'
import ReactDOM from 'react-dom'
import { styled } from 'classnames-in-js'

const Heading = styled('h1', 'heading')
const DarkHeading = styled(Heading, 'heading--dark')
const EvenDarkerHeading = styled(DarkHeading, 'heading--even-darker')

ReactDOM.render(
  <>
    <Heading>Hello</Heading>
    <DarkHeading>Hello</DarkHeading>
    <EvenDarkerHeading>Hello</EvenDarkerHeading>
  </>,
  document.body
)

// <h1 class="heading">Hello</h1>
// <h1 class="heading heading--dark">Hello</h1>
// <h1 class="heading heading--dark heading--even-darker">Hello</h1>

Theming

import React from 'react'
import ReactDOM from 'react-dom'
import { styled, Theme } from 'classnames-in-js'

const Heading = styled('h1', (props, theme) => `heading heading--${theme}`)

ReactDOM.render(
  <Theme.Provider value={'sport'}>
    <Heading>Hello</Heading>
  </Theme.Provider>,
  document.body
)

// <h1 class="heading heading--sport">Hello</h1>

Tagged template literal API

classnames-in-js also supports using tagged template literals to construct classes.

If an interpolated value is a function it will be called with the props and the theme if present.

import React from 'react'
import ReactDOM from 'react-dom'
import { styled, Theme } from 'classnames-in-js'

const Heading = styled.h1`
  heading
  ${Date.now() === 42 ? 'heading--dark' : ''}
  ${(props, theme) => `heading--${theme}`}
`

ReactDOM.render(
  <Theme.Provider value={'sport'}>
    <Heading>Hello</Heading>
  </Theme.Provider>,
  document.body
)

// <h1 class="heading heading--dark heading--sport">Hello</h1>

Preact

import styled from 'classnames-in-js/preact'

Note: classnames-in-js/preact does not currently support automaticly extracting theming from context or the tagged template literal api. This is on the todo list.

See also

License

MIT.

About

💠A more sane approach to CSS in React (and Preact) apps

Resources

License

Stars

Watchers

Forks

Packages

No packages published