npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

class-variant

v2.0.2

Published

Create reusable and extensible style class variants

Downloads

645

Readme

Features

Vanilla, Next, React, Vue, Tailwind CSS, and Master CSS are available:

  • ⚡️ Ultra-lightweight ~1.5KB, powered by Proxy
  • 🛡️ Type safety
  • 🌈 Dynamically change styles based on properties
  • 💫 Re-expand existing elements, like NextLink
  • 🧩 Compatible with server and client components
  • 🪄 Built-in first-class clsx handling

Why?

😰 Before: Creating a simple styled element using a FunctionalComponent is unpleasant.

function Button(props) {
    return (
        <button {...props} className={"inline-flex font:14" + (props.className ? ' ' + props.className : '')}>
            {props.children}
        </button>
    )
}

🥳 After: It's in one line and ~80% code less.

import styled from '@master/styled.react' // or .vue

const Button = styled.button`inline-flex font:14`

Apply it as usual:

export default function App() {
    return (
        <Button className="uppercase">submit</Button>
    )
}

It will be rendered as:

<button class="inline-flex font:14 uppercase">submit</button>

Getting Started

Install the package depending on your framework:

Vanilla

npm install class-variant
import cv from 'class-variant'

const btn = cv(...params)
const btn = cv`...` // or

btn(props) // -> string

React

npm install @master/styled.react
import styled from '@master/styled.react'

const Button = styled.button(...params)
const Button = styled.button`...` // or

<Button {...props}>

Vue

npm install @master/styled.vue
import styled from '@master/styled.vue'

const Button = styled.button(...params)
const Button = styled.button`...` // or

<Button {...props}>

Basic usage

Create a styled element

Declared in two ways: function or template literal, and parameters inherit all features of clsx.

const Element = styled.div`flex text:center`
const Element = styled.div('flex text:center') // or

return (
    <Element className="uppercase">Hello World</Element>
)
<div class="flex text:center uppercase">Hello World</div>

Apply based on predefined variants

Predefine the class variant corresponding to the property.

const Button = styled.button('flex', {
    $size: {
        sm: 'font:12 size:8x',
        md: 'font:14 size:12x'
    },
    disabled: 'opacity:.5',
    ...
})

return (
    <Button $size="sm" disabled />
)
<button class="flex font:12 size:8x opacity:.5" disabled></button>

⚠️ Custom properties that are not element-owned properties must be prefixed with $prop, otherwise they will be reflected on the final element and an error may be thrown.

You can set default properties for elements.

Button.defaultProps = {
    $size: 'md'
}

return (
    <Button />
)
<button class="font:14 size:12x"></button>

Apply based on function properties

Dynamically apply class names based on function properties.

const Element = styled.div('fg:white',
    ({ $color }) => $color && `bg:${$color}`
)

return (
    <Element $color="blue" />
)
<div class="inline-flex text:center fg:white bg:blue"></div>

Apply based on matching properties

Applies the target class name matching all specified property keys and their values.

const Button = styled.button('inline-flex',
    ['uppercase', { $intent: 'primary', $size: 'md' }]
)

return (
    <Button $intent="primary">Not matched</button>
    <Button $size="md">Not matched</button>
    <Button $intent="primary" $size="md">Matched</button>
)
<button class="inline-flex">Not matched</button>
<button class="inline-flex">Not matched</button>
<button class="inline-flex uppercase">Matched</button>

Extended

Extend a styled element

Extend an existing styled element and add additional classes or conditions.

const A = styled.p('a')
const B = styled.p(A)`b`

return (
    <A>A</A>
    <B>B</B>
)
<p class="a">A</p>
<p class="a b">B</p>

Change an element's tag name

Changing the original tag name of an element, such as <button> to <a>. Left empty '' even if there are no additional classes.

const Button = styled.button('inline-flex')
const Link = styled.a(Button)``

return (
    <Button>button</Button>
    <Link href="#example">link</Link>
)
<button class="inline-flex">button</button>
<a class="inline-flex" href="#example">link</a>

Extend multiple styled elements

Extend multiple style elements at once.

const A = styled.p`a`
const B = styled.p`b`
const C = styled.p`c`
const D = styled(A)(B)(C)`d`

return (
    <A>A</A>
    <B>B</B>
    <C>C</C>
    <D>D</D>
)
<p class="a">A</p>
<p class="b">B</p>
<p class="c">C</p>
<p class="a b c d">D</p>

Typings

declare type Props = {
    $size: 'sm' | 'md'
}

const Button = styled.button<Props>('flex', {
    $size: {
        sm: 'font:12 size:8x',
        md: 'font:14 size:12x'
    },
    disabled: 'opacity:.5'
})

Overview class-variant APIs

import cv from 'class-variant'

const btn = cv(
    'inline-flex rounded',
    {
        intent: {
            primary: 'bg:blue fg:white bg:blue-60:hover',
            secondary: 'bg:white fg:slate-30 bg:slate-90:hover',
        },
        size: {
            sm: 'text:14 p:5|15',
            md: 'text:16 p:10|25'
        }
    },
    ['uppercase', { intent: 'primary', size: 'md' }],
    ({ indent, size }) => indent && size && 'font:semibold'
)

btn.default = {
    intent: 'primary',
    size: 'sm'
}

btn()
// inline-flex rounded bg:blue fg:white bg:blue-55:hover text:14 p:5|8 font:semibold

btn({ indent: 'secondary', size: 'sm' })
// inline-flex rounded bg:white fg:slate-30 bg:slate-90:hover text:14 p:5|8 font:semibold

btn({ indent: 'primary', size: 'md' })
// inline-flex rounded bg:blue fg:white bg:blue-55:hover text:16 p:10|25 uppercase font:semibold

Community

The Master community can be found here:

Our 《 Code of Conduct 》 applies to all Master community channels.

Contributing

Please see our CONTRIBUTING for workflow.

Inspiration

Some of our core concepts and designs are inspired by these giants.

  • Template Literal - The use of template literals as syntactic sugar for reusing components is inspired by Styled Components.