@slicknode/stylemapper
TypeScript icon, indicating that this package has built-in type declarations

0.1.5 • Public • Published

Slicknode Stylemapper

npm version Build passing Test Coverage License Dependency Count Types included

Easily create styled, strictly typed React components and simplify your component code.

Stylemapper is a small, flexible and zero-dependency utility to add CSS classes to React components. It eliminates the boilerplate you usually need for changing styles based on state, define typescript definitions, etc. This simplifies the creation and maintenance of your style and design system:

  • Get strictly typed components without writing Typescript prop type definitions (Stylemapper infers types automatically)
  • Automatically create variant props without complicating your component code (success/error, large/medium etc.)
  • Add styles to 3rd party libraries without manually creating wrapper components, type definitions, etc.
  • Have a single source of truth for your styles instead of spreading classnames all over your React components

Works especially great with utility based CSS frameworks like Tailwind CSS.

Installation

Add Slicknode Stylemapper as a dependency to your project:

npm install --save @slicknode/stylemapper

Usage

Import the styled utility function and create styled components. Examples are using Tailwind CSS utility classes.

Basic Example

import { styled } from '@slicknode/stylemapper';

// Create styled components with CSS classes
const Menu = styled('ul', 'space-x-2 flex');
const MenuItem = styled('li', 'w-9 h-9 flex items-center justify-center');

// Then use the components in your app
const App = () => {
  return (
    <Menu>
      <MenuItem>Home</MenuItem>
      <MenuItem>Product</MenuItem>
      <MenuItem>Signup Now</MenuItem>
    </Menu>
  );
};

Variants

Create variants by passing a configuration object. Stylemapper automatically infers the correct prop type definitions and passes the resulting className prop to the component:

const Button = styled('button', {
  variants: {
    intent: {
      neutral: 'bg-slate-300 border border-slate-500',
      danger: 'bg-red-300 border border-red-500',
      success: 'bg-green-300 border border-green-500',
    },
    size: {
      small: 'p-2',
      medium: 'p-4',
      large: 'p-8',
    },
    // Add any number of variants...
  },
  // Optionally set default variant values
  defaultVariants: {
    intent: 'neutral',
    size: 'medium',
  },
});

const App = () => {
  return (
    <Button intent={'danger'} size={'large'}>
      Delete Account
    </Button>
  );
};

Compound Variants

If you only want to add class names to a component if multiple props have particular values, you can configure compountVariants:

const Button = styled('button', {
  variants: {
    intent: {
      danger: 'bg-red-300',
      success: 'bg-green-300',
    },
    outline: {
      true: 'border',
      false: '',
    },
    // Add any number of variants...
  },
  compoundVariants: [
    {
      intent: 'success',
      outline: true,
      className: 'border-green-500',
    },
    {
      intent: 'danger',
      outline: true,
      className: 'border-red-500',
    },
  ],
});

const App = () => {
  return (
    <Button intent={'danger'} outline>
      Delete Account
    </Button>
  );
};

Custom Components

Stylemapper works with any React component, as long as the component has a className prop. This makes it easy to add styles to your own components or to UI libraries like Headless UI, Radix UI and Reach UI. Just pass in the component as a first argument:

const CustomComponent = ({ className }) => {
  return (
    // Make sure you add the className from the props to the DOM node
    <div className={className}>My custom react component</div>
  );
};

const StyledCustomComponent = styled(CustomComponent, {
  variants: {
    intent: {
      danger: 'bg-red-300 border border-red-500',
      success: 'bg-green-300 border border-green-500',
    },
  },
});

// Extending styled components
const SizedComponent = styled(StyledCustomComponent, {
  variants: {
    size: {
      small: 'p-2',
      medium: 'p-4',
      large: 'p-8',
    },
  },
});

const App = () => {
  return (
    <SizedComponent intent="danger" size="large">
      Large error message
    </SizedComponent>
  );
};

Variant Type Casting

You can define boolean and numeric variant values. The type definition for the resulting prop is automatically inferred:

const StyledComponent = styled('div', {
  variants: {
    selected: {
      true: 'bg-red-300 border border-red-500',
      false: 'bg-green-300 border border-green-500',
    },
    size: {
      1: 'p-2'
      2: 'p-4'
      3: 'p-8'
    }
  },
});

const App = () => (
  // This component now expects a boolean and a number value as props
  <StyledComponent selected={true} size={2}/>
);

Prop Forwarding

By default, variant props are not passed to the wrapped component to prevent invalid props to be attached to DOM nodes. If you need the values of variants inside of your custom components, specify them in the configuration:

const CustomComponent = ({ open, className }) => {
  return (
    <div className={className}>Component is {open ? 'open' : 'closed'}</div>
  );
};

const StyledComponent = styled('div', {
  variants: {
    selected: {
      true: 'bg-red-300 border border-red-500',
      false: 'bg-green-300 border border-green-500',
    },
  },
  forwardProps: ['selected'],
});

Composing Configurations

You can pass any number of configurations to the styled function. This allows you to reuse styles and variants across components. Pass either a string with class names or a configuration object as input values:

import { intentVariants, sizeVariants } from './shared';
const StyledComponent = styled(
  'div',

  // Add some base styles that are added every time
  'p-2 flex gap-2',

  // Add imported variants
  intentVariants,
  sizeVariants,

  // Add other custom variants
  {
    selected: {
      true: 'border border-green-500',
      false: 'border border-green-100',
    },
  }
);

IntelliSense for Tailwind CSS

If you are using the offical TailwindCSS extension for VSCode, you can enable intellisense for style mapper by updating your settings:

{
  "tailwindCSS.experimental.classRegex": [
    ["styled\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
  ]
}

Credits

This library is heavily inspired by Stitches, a great CSS in Javascript library. Stylemapper brings a similar API to utility based CSS frameworks without requiring a specific library.

Package Sidebar

Install

npm i @slicknode/stylemapper

Weekly Downloads

316

Version

0.1.5

License

MIT

Unpacked Size

74.2 kB

Total Files

12

Last publish

Collaborators

  • ivome