rececss

Minimalistic, fully customizable CSS utilities generator

Usage no npm install needed!

<script type="module">
  import rececss from 'https://cdn.skypack.dev/rececss';
</script>

README

rececss

Minimalistic, fully customizable CSS utilities generator

License NPM Version CI Code Coverage

Usage

Create a rececss.config.js file at the root of your project:

module.exports = {
  output: {
    path: "./path/to/css",
  },
  rules: {
    width: {
      full: "100%", 
      half: "50%",
      $px: [[0, 50, 10], 100, 500], // supports ranges in a [start, stop, step] form
    },
    color: { dark: "#000", light: "#fff" },
    ...
  },
}

And simply run:

$ npx rececss

The generated CSS assets will be placed at ./path/to/css/rececss.css and contain the following rulesets:

.w_full { width: 100%; } .miw_full { min-width: 100%; } .maw_full { max-width: 100%; }
.w_half { width: 50%; }  .miw_half { min-width: 50%; }  .maw_half { max-width: 50%; }

.w_0   { width: 0px; }   .miw_0   { min-width: 0px; }   .maw_0   { max-width: 0px; }
.w_10  { width: 10px; }  .miw_10  { min-width: 10px; }  .maw_10  { max-width: 10px; }
.w_20  { width: 20px; }  .miw_20  { min-width: 20px; }  .maw_20  { max-width: 20px; }
.w_30  { width: 30px; }  .miw_30  { min-width: 30px; }  .maw_30  { max-width: 30px; }
.w_40  { width: 40px; }  .miw_40  { min-width: 40px; }  .maw_40  { max-width: 40px; }
.w_50  { width: 50px; }  .miw_50  { min-width: 50px; }  .maw_50  { max-width: 50px; }
.w_100 { width: 100px; } .miw_100 { min-width: 100px; } .maw_100 { max-width: 100px; }
.w_500 { width: 500px; } .miw_500 { min-width: 500px; } .maw_500 { max-width: 500px; }

.c_dark  { color: #000; }
.c_light { color: #fff; }

// ... 

⚠️ You may want to get rid of unused classnames in production. Check out PurgeCSS.

Motivation || "Why not tailwind?"

  1. Autogenerated unit values. Range syntax support.
  2. Ability to split output files by media queries.
  3. More control over state utilities (:hover, :active, js states).
  4. Rich classnames customization that default to Emmet abbreviations.

Customization

Output

Specifies the output settings of the result CSS assets.

  • path (string) - All of the generated assets will be placed into this directory. Defaults to ..
  • filename (string) - Common filename which will be given to all of the generated assets. Defaults to rececss.
  • extension ("css" | "scss") - Extension of the generated assets. Defaults to css.
  • splitByMedia (boolean) - Weather split generated assets for each media or keep it in a single file. Defaults to false

For example, using the following rececss.config.js

module.exports = {
  output: {
    path: "path/to/css",
    filename: "utils",
    extension: "css",
    splitByMedia: true,
  },
  media: {
    prnt: "print",
    scr: "screen"
  },
  ...
}

will result in:

├── path
│   └── to
│       └── css
│           ├── utils.css
│           ├── utils.prnt.css
│           └── utils.scr.css
└── rececss.config.js

Media

Sets up the map of media queries to be used in generated assets where keys are used as prefixes for classnames. For example the config below:

module.exports = {
  output: {
    splitByMedia: true,
  },
  sep: {
    media: "-",
  },
  media: {
    md: "only screen and (min-width: 768px)",
    lg: "only screen and (min-width: 1024px)"
  },
  rules: {
    color: { dark: "#000" },
  }
  ...
}

will generate assets with the following rulesets:

/* rececss.css */
.c_dark { color: #000; }
...
/* rececss.md.css */
@media only screen and (min-width: 768px) {
  .md-c_dark { color: #000; }
  ...
}
/* rececss.lg.css */
@media only screen and (min-width: 1024px) {
  .lg-c_dark { color: #000; }
  ...
}

States (:hover, :focus, :active, etc.)

Here is the place where you can define pseudo-class or javasript driven utility states that would be applied to all of the generated rulesets.

module.exports = {
  ...
  sep: {
    state: "-"
  },
  states: {
    hov: "$0:hover",
    hovParent: ":hover > $0",
    js: "$0.js-active",
  },
  rules: {
    margin: { shorthand: { "0a": "0 auto" }},
    color: { dark: "#000", light: "#fff" },
  },
}

In the above config $0 in states represents a classname that would be inserted after processing. Keys are used as suffixes for this classnames. Check out the result:

.m_0a,
.m_0a-hov:hover,
*:hover > .m_0a-hovParent,
.m_0a-js.js-active {
  margin: 0 auto;
}
.c_dark,
.c_dark-hov:hover,
*:hover > .c_dark-hovParent,
.c_dark-js.js-active {
  color: #000;
}
.c_light,
.c_light-hov:hover,
*:hover > .c_light-hovParent,
.c_light-js.js-active {
  color: #fff;
}

Increasing specificity

The are scenarios when you need to make some classes more specific then the others. Here is an example of such usecase. You can achieve that with states as well:

module.exports = {
  ...
  sep: { 
    state: "-" 
  },
  states: {
    "!": "$0$0",
  },
  rules: {
    color: { dark: "#000", light: "#fff" },
  },
}

That'll generate the dubplicated classnames like so:

.c_dark, .c_dark-\\!.c_dark-\\! { color: #000; }
.c_light, .c_light-\\!.c_light-\\! { color: #fff; }

So that .c_dark-! and .c_light-! would be more specific then theirs normal variants:

<span class="c_light c_dark-!">This texts color is #000<span>

And you can ofcourse add as many levels of specificity as you need.

Rules

Most of the rules follows minimal conventions for generating values. Each rule gets described thought an object where regular keys are being used as classname suffixes and their values inserted into CSS declaration. In addition you could provide unit keywords starting with $ ($px, $em, $rem, $pct, ect) with array of numbers and ranges ([start, stop, step]) as a value:

rule: { 
  md: "16px", 
  lg: "24px",
  $px: [20, 30, [8, 16, 2]], // => 8px, 10px, 12px, 14px, 16px, 20px, 30px
  $pct: [[50, 80, 10], 100, 150], // => 50%, 60%, 70%, 80%, 100%, 150%
  $em: [1, [2, 5, 1]], // => 1em, 2em, 3em, 4em, 5em
  $rem: [1, [1.1, 2, 0.1]], // => 1rem, 1.1rem, 1.2rem, 1.3rem, 1.4rem, 1.5rem, 1.6rem, 1.7rem, 1.8rem, 1.9rem, 2rem
  $num: [-1, 0, 1], // => -1, 0, 1
  $vw: [50, 90], // => 50vw, 90vw
  $vh: [10, 100], // => 10vh, 100vh
  $cm: [...],
  $mm: [...],
  $Q: [...],
  $in: [...],
  $pc: [...],
  $pt: [...],
  $ex: [...],
  $ch: [...],
  $lh: [...],
  $vmin: [...],
  $vmax: [...],
  $percent: [...], // alias for $pct 
  $number: [...] // alias for $num 
}

Width

Ruleset Key Default Classname Declarations
widthAuto w_a { width: auto; }
width w_$0 { width: $0; }
minWidth miw_$0 { min-width: $0; }
maxWidth maw_$0 { max-width: $0; }
module.exports = {
  // ...
  rules: {
    width: {
      full: "100%", 
      half: "50%",
      $px: [[0, 50, 5], [100, 1000, 100]], 
      $pct: [[0, 100, 10]]
    },
  }
}

Outputs:

.w_a    { width: auto; }
.w_full { width: 100%; } .miw_full { min-width: 100%; } .maw_full { max-width: 100%; }
.w_half { width: 50%; }  .miw_half { min-width: 50%; }  .maw_half { max-width: 50%; }
.w_0    { width: 0px; }  .miw_0    { min-width: 0px; }  .maw_0    { max-width: 0px; }
.w_5    { width: 5px; }  .miw_5    { min-width: 5px; }  .maw_5    { max-width: 5px; }
.w_10   { width: 10px; } .miw_10   { min-width: 10px; } .maw_10   { max-width: 10px; }
...
.w_50  { width: 50px; }  .miw_50  { min-width: 50px; }  .maw_50  { max-width: 50px; }
.w_100 { width: 100px; } .miw_100 { min-width: 100px; } .maw_100 { max-width: 100px; }
.w_200 { width: 200px; } .miw_200 { min-width: 200px; } .maw_200 { max-width: 200px; }
...
.w_1000 { width: 1000px; } .miw_1000 { min-width: 1000px; } .maw_1000 { max-width: 1000px; }
.w_0\%  { width: 0%; }     .miw_0\%  { min-width: 0%; }     .maw_0\%  { max-width: 0%; }
.w_10\% { width: 10%; }    .miw_10\% { min-width: 10%; }    .maw_10\% { max-width: 10%; }
.w_20\% { width: 20%; }    .miw_20\% { min-width: 20%; }    .maw_20\% { max-width: 20%; }
...
.w_100\% { width: 100%; } .miw_100\% { min-width: 100%; } .maw_100\% { max-width: 100%; }

Height

Ruleset Key Default Classname Declarations
heightAuto h_a { height: auto; }
height h_$0 { height: $0; }
minHeight mih_$0 { min-height: $0; }
maxHeight mah_$0 { max-height: $0; }
module.exports = {
  // ...
  rules: {
    height: {
      full: "100%",
      $px: [300, 50], 
      $vh: [[0, 100, 10]],
    }
  }
}

Outputs:

.h_a    { height: auto; }
.h_full { height: 100%; }  .mih_full { min-height: 100%; }  .mah_full { max-height: 100%; }
.h_50   { height: 50px; }  .mih_50   { min-height: 50px; }  .mah_50   { max-height: 50px; }
.h_300  { height: 300px; } .mih_300  { min-height: 300px; } .mah_300  { max-height: 300px; }
.h_0vh  { height: 0vh; }   .mih_0vh  { min-height: 0vh; }   .mah_0vh  { max-height: 0vh; }
.h_10vh { height: 10vh; }  .mih_10vh { min-height: 10vh; }  .mah_10vh { max-height: 10vh; }
...
.h_100vh { height: 100vh; } .mih_100vh { min-height: 100vh; } .mah_100vh { max-height: 100vh; }

Margin

module.exports = {
  // ...
  rules: {
    margin: {
      shorthand: { a: "auto", "0a": "0 auto" },
      edges: { sm: "10px", md: "15px", lg: "30px", $px: [[0, 50, 5]] },
    }
  }
}
Shorthand
Ruleset Key Default Classname Declarations
margin m_$0 { margin: $0; }

Outputs:

.m_a { margin: auto; }
.m_0a { margin: 0 auto; }
Edges
Ruleset Key Default Classname Declarations
margin m_$0 { margin: $0; }
marginTop mt_$0 { margin-top: $0; }
marginBottom mb_$0 { margin-bottom: $0; }
marginVertical mv_$0 { margin-top: $0; margin-bottom: $0; }
marginLeft ml_$0 { margin-left: $0; }
marginRight mr_$0 { margin-right: $0; }
marginHorizontal mh_$0 { margin-left: $0; margin-right: $0; }

And outputs:

.m_sm { margin: 10px; } .mt_sm { margin-top: 10px; } .mb_sm { margin-bottom: 10px; } .mver_sm { margin-top: 10px; margin-bottom: 10px; } .ml_sm { margin-left: 10px; } .mr_sm { margin-right: 10px; } .mhor_sm { margin-left: 10px; margin-right: 10px; }
.m_md { margin: 15px; } .mt_md { margin-top: 15px; } .mb_md { margin-bottom: 15px; } .mver_md { margin-top: 15px; margin-bottom: 15px; } .ml_md { margin-left: 15px; } .mr_md { margin-right: 15px; } .mhor_md { margin-left: 15px; margin-right: 15px; }
.m_lg { margin: 30px; } .mt_lg { margin-top: 30px; } .mb_lg { margin-bottom: 30px; } .mver_lg { margin-top: 30px; margin-bottom: 30px; } .ml_lg { margin-left: 30px; } .mr_lg { margin-right: 30px; } .mhor_lg { margin-left: 30px; margin-right: 30px; }
.m_0  { margin: 0px; } .mt_0 { margin-top: 0px; } .mb_0 { margin-bottom: 0px; } .mver_0 { margin-top: 0px; margin-bottom: 0px; } .ml_0 { margin-left: 0px; } .mr_0 { margin-right: 0px; } .mhor_0 { margin-left: 0px; margin-right: 0px; }
.m_5  { margin: 5px; } .mt_5 { margin-top: 5px; } .mb_5 { margin-bottom: 5px; } .mver_5 { margin-top: 5px; margin-bottom: 5px; } .ml_5 { margin-left: 5px; } .mr_5 { margin-right: 5px; } .mhor_5 { margin-left: 5px; margin-right: 5px; }
...
.m_50 { margin: 50px; } .mt_50 { margin-top: 50px; } .mb_50 { margin-bottom: 50px; } .mver_50 { margin-top: 50px; margin-bottom: 50px; } .ml_50 { margin-left: 50px; } .mr_50 { margin-right: 50px; } .mhor_50 { margin-left: 50px; margin-right: 50px; }

Padding

module.exports = {
  // ...
  rules: {
    padding: {
      shorthand: { a: "auto", card: "20px 10px 40px" },
      edges: { sm: "10px", md: "15px", $em: [[1, 3, 0.5]] },
    }
  }
}
Shorthand
Ruleset Key Default Classname Declarations
padding p_$0 { padding: $0; }
.p_a { padding: auto; }
.p_card { padding: 20px 10px 40px; }
Edges
Ruleset Key Default Classname Declarations
padding p_$0 { padding: $0; }
paddingTop pt_$0 { padding-top: $0; }
paddingBottom pb_$0 { padding-bottom: $0; }
paddingVertical pv_$0 { padding-top: $0; padding-bottom: $0; }
paddingLeft pl_$0 { padding-left: $0; }
paddingRight pr_$0 { padding-right: $0; }
paddingHorizontal ph_$0 { padding-left: $0; padding-right: $0; }

Outputs:

.p_sm      { padding: 10px; } .pt_sm { padding-top: 10px; } .pb_sm { padding-bottom: 10px; } .pver_sm { padding-top: 10px; padding-bottom: 10px; } .pl_sm { padding-left: 10px; } .pr_sm { padding-right: 10px; } .phor_sm { padding-left: 10px; padding-right: 10px; }
.p_md      { padding: 15px; } .pt_md { padding-top: 15px; } .pb_md { padding-bottom: 15px; } .pver_md { padding-top: 15px; padding-bottom: 15px; } .pl_md { padding-left: 15px; } .pr_md { padding-right: 15px; } .phor_md { padding-left: 15px; padding-right: 15px; }
.p_1em     { padding: 1em; } .pt_1em { padding-top: 1em; } .pb_1em { padding-bottom: 1em; } .pver_1em { padding-top: 1em; padding-bottom: 1em; } .pl_1em { padding-left: 1em; } .pr_1em { padding-right: 1em; } .phor_1em { padding-left: 1em; padding-right: 1em; }
.p_1\.5em  { padding: 1.5em; } .pt_1\.5em { padding-top: 1.5em; } .pb_1\.5em { padding-bottom: 1.5em; } .pver_1\.5em { padding-top: 1.5em; padding-bottom: 1.5em; } .pl_1\.5em { padding-left: 1.5em; } .pr_1\.5em { padding-right: 1.5em; } .phor_1\.5em { padding-left: 1.5em; padding-right: 1.5em; }
...
.p_3em { padding: 3em; } .pt_3em { padding-top: 3em; } .pb_3em { padding-bottom: 3em; } .pver_3em { padding-top: 3em; padding-bottom: 3em; } .pl_3em { padding-left: 3em; } .pr_3em { padding-right: 3em; } .phor_3em { padding-left: 3em; padding-right: 3em; }

Offset (top, right, bottom, left)

Ruleset Key Default Classname Declarations
top t_$0 { top: $0; }
bottom b_$0 { bottom: $0; }
left l_$0 { left: $0; }
right r_$0 { right: $0; }
module.exports = {
  // ...
  rules: {
    offset: { 
      sm: "10px", 
      md: "15px", 
      $px: [[0, 100, 5]] 
    },
  }
}

Outputs:

.t_sm { top: 10px; } .b_sm { bottom: 10px; } .l_sm { left: 10px; } .r_sm { right: 10px; }
.t_md { top: 15px; } .b_md { bottom: 15px; } .l_md { left: 15px; } .r_md { right: 15px; }
.t_0  { top: 0px; }  .b_0  { bottom: 0px; }  .l_0  { left: 0px; }  .r_0 { right: 0px; }
.t_5  { top: 5px; }  .b_5  { bottom: 5px; }  .l_5  { left: 5px; }  .r_5 { right: 5px; }
.t_10 { top: 10px; } .b_10 { bottom: 10px; } .l_10 { left: 10px; } .r_10 { right: 10px; }
...
.t_100 { top: 100px; } .b_100 { bottom: 100px; } .l_100 { left: 100px; } .r_100 { right: 100px; }

Flex

module.exports = {
  // ...
  rules: {
    flex: {
      shorthand: { "00a": "0 0 auto", norm: "1", $num: [[1, 10, 1]] },
      basis: { half: "50%", $px: [[100, 500, 100]], $pct: [[0, 100, 20]] },
      grow: { max: 10, $num: [1, 2, 3, 4] },
      shrink: { none: 0, $num: [1, 2, 3] },
      order: { first: 1, $num: [1, -1] },
      grid: {
        cols: 12,
        gutter: "20px",
        gutters: { sm: "10px", lg: "40px"}
      },
    },
  }
}
Shorthand
Ruleset Key Default Classname Declarations
flex fx_$0 { flex: $0; }

Outputs:

.fx_00a { flex: 0 0 auto; }
.fx_norm { flex: 1; }
.fx_1 { flex: 1; }
.fx_2 { flex: 2; }
.fx_3 { flex: 3; }
.fx_4 { flex: 4; }
.fx_5 { flex: 5; }
.fx_6 { flex: 6; }
.fx_7 { flex: 7; }
.fx_8 { flex: 8; }
.fx_9 { flex: 9; }
.fx_10 { flex: 10; }
Basis
Ruleset Key Default Classname Declarations
flexBasis fxb_$0 { flex-basis: $0; }

Outputs:

.fxb_half { flex-basis: 50%; }
.fxb_100 { flex-basis: 100px; }
.fxb_200 { flex-basis: 200px; }
.fxb_300 { flex-basis: 300px; }
.fxb_400 { flex-basis: 400px; }
.fxb_500 { flex-basis: 500px; }
.fxb_0\% { flex-basis: 0%; }
.fxb_20\% { flex-basis: 20%; }
.fxb_40\% { flex-basis: 40%; }
.fxb_60\% { flex-basis: 60%; }
.fxb_80\% { flex-basis: 80%; }
.fxb_100\% { flex-basis: 100%; }
Grow
Ruleset Key Default Classname Declarations
flexGrow fxg_$0 { flex-grow: $0 }

Outputs:

.fxg_max { flex-grow: 10; }
.fxg_1 { flex-grow: 1; }
.fxg_2 { flex-grow: 2; }
.fxg_3 { flex-grow: 3; }
.fxg_4 { flex-grow: 4; }
Shrink
Ruleset Key Default Classname Declarations
flexShrink fxs_$0 { flex-shrink: $0; }

Outputs:

.fxs_none { flex-shrink: 0; }
.fxs_1 { flex-shrink: 1; }
.fxs_2 { flex-shrink: 2; }
.fxs_3 { flex-shrink: 3; }
Order
Ruleset Key Default Classname Declarations
order ord_$0 { order: $0; }

Outputs:

.ord_first { order: 1; }
.ord_1 { order: 1; }
.ord_-1 { order: -1; }
Grid

Generates flexbox grid where

  • cols (number) - total number of columns
  • gutter (string) - default gutter to be used with flexRow
  • gutters (object) - additional gutters to be used with flexRowGuttered
Ruleset Key Default Classname Declarations
flexRow fxrow { display: flex; margin-left: -$0; margin-right: -$0; }
flexRowGuttered fxrow_$0 { display: flex; margin-left: -$0; margin-right: -$0; }
flexCol fxcol_$0 { flex-basis: $0; max-width: $0; }

Outputs:

.fxrow    { display: flex; margin-left: -10px; margin-right: -10px; }
.fxrow_sm { display: flex; margin-left: -5px; margin-right: -5px; }
.fxrow_lg { display: flex; margin-left: -20px; margin-right: -20px; }

.fxrow > *    { flex: 1 0 auto; padding-left: 10px; padding-right: 10px; }
.fxrow_sm > * { flex: 1 0 auto; padding-left: 5px; padding-right: 5px; }
.fxrow_lg > * { flex: 1 0 auto; padding-left: 20px; padding-right: 20px; }

.fxcol_1 { flex-basis: 8.333%; max-width: 8.333%; }
.fxcol_2 { flex-basis: 16.666%; max-width: 16.666%; }
.fxcol_3 { flex-basis: 25%; max-width: 25%; }
.fxcol_4 { flex-basis: 33.333%; max-width: 33.333%; }
.fxcol_5 { flex-basis: 41.666%; max-width: 41.666%; }
.fxcol_6 { flex-basis: 50%; max-width: 50%; }
.fxcol_7 { flex-basis: 58.333%; max-width: 58.333%; }
.fxcol_8 { flex-basis: 66.666%; max-width: 66.666%; }
.fxcol_9 { flex-basis: 75%; max-width: 75%; }
.fxcol_10 { flex-basis: 83.333%; max-width: 83.333%; }
.fxcol_11 { flex-basis: 91.666%; max-width: 91.666%; }
.fxcol_12 { flex-basis: 100%; max-width: 100%; }

Font

module.exports = {
  // ...
  rules: {
    font: {
      shorthand: { primary: "italic bold .8em/1.2 Arial, sans-serif" },
      size: { xs: "8px", sm: "12px", md: "16px", $px: [[8, 16, 2]] },
      family: { primary: "Arial, serif", secondary: "Helvetica, sans-serif" },
      lineHeight: { xs: "8px", sm: "12px", md: "16px", $em: [[1, 5, 1]], $num: [1, 2, [3, 4, 0.2]] }
    }
  }
}
Shorthand
Ruleset Key Default Classname Declarations
font f_$0 { font: $0; }

Outputs:

.f_primary { font: italic bold .8em/1.2 Arial, sans-serif; }
Size
Ruleset Key Default Classname Declarations
fontSize fz_$0 { font-size: $0; }

Outputs:

.fz_xs { font-size: 8px; }
.fz_sm { font-size: 12px; }
.fz_md { font-size: 16px; }
.fz_8 { font-size: 8px; }
.fz_10 { font-size: 10px; }
.fz_12 { font-size: 12px; }
.fz_14 { font-size: 14px; }
.fz_16 { font-size: 16px; }
Family
Ruleset Key Default Classname Declarations
fontFamily ff_$0 { font-family; $0; }

Outputs:

.ff_primary { font-family: Arial, serif; }
.ff_secondary { font-family: Helvetica, sans-serif; }
Line Height
Ruleset Key Default Classname Declarations
lineHeight lh_$0 { line-height: $0; }

Outputs:

.lh_xs { line-height: 8px; }
.lh_sm { line-height: 12px; }
.lh_md { line-height: 16px; }
.lh_1em { line-height: 1em; }
.lh_2em { line-height: 2em; }
.lh_3em { line-height: 3em; }
.lh_4em { line-height: 4em; }
.lh_5em { line-height: 5em; }
.lh_1 { line-height: 1; }
.lh_2 { line-height: 2; }
.lh_3 { line-height: 3; }
.lh_3\.2 { line-height: 3.2; }
.lh_3\.4 { line-height: 3.4; }
.lh_3\.6 { line-height: 3.6; }
.lh_3\.8 { line-height: 3.8; }
.lh_4 { line-height: 4; }

Border

module.exports = {
  // ...
  rules: {
    border: {
      shorthand: { thin: "1px solid black", bold: "5px solid black" },
      radius: { circle: "50%", $px: [5, 10] },
    },
  }
}
Shorthand
Ruleset Key Default Classname Declarations
border bd_$0 { border: $0; }
borderLeft bdl_$0 { border-left: $0; }
borderRight bdr_$0 { border-right: $0; }
borderTop bdt_$0 { border-top: $0; }
borderBottom bdb_$0 { border-bottom: $0; }

Outputs:

.bd_thin { border: 1px solid black; }
.bdt_thin { border-top: 1px solid black; }
.bdb_thin { border-bottom: 1px solid black; }
.bdl_thin { border-left: 1px solid black; }
.bdr_thin { border-right: 1px solid black; }

.bd_bold { border: 5px solid black; }
.bdt_bold { border-top: 5px solid black; }
.bdb_bold { border-bottom: 5px solid black; }
.bdl_bold { border-left: 5px solid black; }
.bdr_bold { border-right: 5px solid black; }
Radius
Ruleset Key Default Classname Declarations
borderRadius bdrs_$0 { border-radius: $0; }

Outputs:

.bdrs_5 { border-radius: 5px; }
.bdrs_10 { border-radius: 10px; }
.bdrs_circle { border-radius: 50%; }

Colors

Ruleset Key Default Classname Declarations
color c_$0 { color: $0 }
module.exports = {
  // ...
  rules: {
    color: { dark: "#000", light: "#fff" }
  }
}

Outputs:

.c_dark { color: #000; }
.c_light { color: #fff; }

Statics

Beyond the configurable rulesets there are ones that corresponds to the rest of CSS properties with every possible keyword value.

Position
Ruleset Key Default Classname Declarations
positionStatic pos_s { position: static;}
positionRelative pos_r { position: relative; }
positionAbsolute pos_a { position: absolute; }
positionFixed pos_f { position: fixed; }
Display
Ruleset Key Default Classname Declarations
displayNone d_n { display: none; }
displayInline d_i { display: inline; }
displayBlock d_b { display: block; }
displayInlineBlock d_ib { display: inline-block; }
displayFlex d_f { display: flex; }
displayInlineFlex d_if { display: inline-flex; }
displayTable d_t { display: table; }
displayGrid d_g { display: grid; }
displayInlineGrid d_ig { display: inline-grid; }
Visibility
Ruleset Key Default Classname Declarations
visibilityVisible v_v { visibility: visible; }
visibilityHidden v_h { visibility: hidden; }
visibilityCollapse v_c { visibility: collapse; }
Vertical Align
Ruleset Key Default Classname Declarations
verticalAlignSuper va_sup { vertical-align: super; }
verticalAlignTop va_t { vertical-align: top; }
verticalAlignTextTop va_tt { vertical-align: text-top; }
verticalAlignMiddle va_m { vertical-align: middle; }
verticalAlignBaseline va_bl { vertical-align: baseline; }
verticalAlignBottom va_b { vertical-align: bottom; }
verticalAlignTextBottom va_tb { vertical-align: text-bottom; }
verticalAlignSub va_sub { vertical-align: sub; }
Text Align
Ruleset Key Default Classname Declarations
textAlignLeft ta_l { text-align: left; }
textAlignCenter ta_c { text-align: center; }
textAlignRight ta_r { text-align: right; }
textAlignJustify ta_j { text-align: justify; }
textAlignLastAuto tal_a { text-align-last: auto; }
textAlignLastLeft tal_l { text-align-last: left; }
textAlignLastCenter tal_c { text-align-last: center; }
textAlignLastRight tal_r { text-align-last: right; }
Text Decoration
Ruleset Key Default Classname Declarations
textDecorationNone td_n { text-decoration: none; }
textDecorationUnderline td_u { text-decoration: underline; }
textDecorationOverline td_o { text-decoration: overline; }
textDecorationLineThrough td_l { text-decoration: line-through; }
Text Emphasis
Ruleset Key Default Classname Declarations
textEmphasisNone te_n { text-emphasis: none; }
textEmphasisAccent te_ac { text-emphasis: accent; }
textEmphasisDot te_dt { text-emphasis: dot; }
textEmphasisCircle te_c { text-emphasis: circle; }
textEmphasisDisc te_ds { text-emphasis: disc; }
textEmphasisBefore te_b { text-emphasis: before; }
textEmphasisAfter te_a { text-emphasis: after; }
Text Transform
Ruleset Key Default Classname Declarations
textTransformNone tt_n { text-transform: none; }
textTransformCapitalize tt_c { text-transform: capitalize; }
textTransformUppercase tt_u { text-transform: uppercase; }
textTransformLowercase tt_l { text-transform: lowercase; }
White Space
Ruleset Key Default Classname Declarations
whiteSpaceNormal whs_n { white-space: normal; }
whiteSpacePre whs_p { white-space: pre; }
whiteSpaceNoWrap whs_nw { white-space: nowrap; }
whiteSpacePreWrap whs_pw { white-space: pre-wrap; }
whiteSpacePreLine whs_pl { white-space: pre-line; }
Flex Direction
Ruleset Key Default Classname Declarations
flexDirectionColumn fxd_c { flex-direction: column; }
flexDirectionColumnReverse fxd_cr { flex-direction: column-reverse; }
flexDirectionRow fxd_r { flex-direction: row; }
flexDirectionRowReverse fxd_rr { flex-direction: row-reverse; }
Flex Wrap
Ruleset Key Default Classname Declarations
flexWrapNoWrap fxw_n { flex-wrap: nowrap; }
flexWrapWrap fxw_w { flex-wrap: wrap; }
flexWrapWrapReverse fxw_we { flex-wrap: wrap-reverse; }
flexWrapUnset fxw_u { flex-wrap: unset; }
Justify Content
Ruleset Key Default Classname Declarations
justifyContentUnset jc_u { justify-content: unset; }
justifyContentCenter jc_c { justify-content: center; }
justifyContentFlexEnd jc_fe { justify-content: flex-end; }
justifyContentFlexStart jc_fs { justify-content: flex-start; }
justifyContentSpaceAround jc_sa { justify-content: space-around; }
justifyContentSpaceBetween jc_sb { justify-content: space-between; }
Align Content
Ruleset Key Default Classname Declarations
alignContentCenter ac_c { align-content: center; }
alignContentFlexEnd ac_fe { align-content: flex-end; }
alignContentFlexStart ac_fs { align-content: flex-start; }
alignContentStretch ac_s { align-content: stretch; }
alignContentSpaceAround ac_sa { align-content: space-around; }
alignContentSpaceBetween ac_sb { align-content: space-between; }
Align Items
Ruleset Key Default Classname Declarations
alignItemsBaseline ai_b { align-items: baseline; }
alignItemsСenter ai_c { align-items: center; }
alignItemsFlexEnd ai_fe { align-items: flex-end; }
alignItemsFlexStart ai_fs { align-items: flex-start; }
alignItemsStretch ai_s { align-items: stretch; }
Background
Ruleset Key Default Classname Declarations
backgroundPositionTop bgp_t { background-position: top; }
backgroundPositionBottom bgp_b { background-position: bottom; }
backgroundPositionLeft bgp_l { background-position: left; }
backgroundPositionRight bgp_r { background-position: right; }
backgroundPositionCenter bgp_c { background-position: center; }
Border
Ruleset Key Default Classname Declarations
borderNone bd_n { border: none; }
borderLeftNone bdl_n { border-left: none; }
borderRightNone bdr_n { border-right: none; }
borderTopNone bdt_n { border-top: none; }
borderBottomNone bdb_n { border-bottom: none; }
Opacity
Ruleset Key Default Classname Declarations
opacity0 op_0 { opacity: 0; }
opacity01 op_01 { opacity: 0.1; }
opacity02 op_02 { opacity: 0.2; }
opacity03 op_03 { opacity: 0.3; }
opacity04 op_04 { opacity: 0.4; }
opacity05 op_05 { opacity: 0.5; }
opacity06 op_06 { opacity: 0.6; }
opacity07 op_07 { opacity: 0.7; }
opacity08 op_08 { opacity: 0.8; }
opacity09 op_09 { opacity: 0.9; }
opacity1 op_1 { opacity: 1; }
Overflow
Ruleset Key Default Classname Declarations
overflowVisible ov_v { overflow: visible; }
overflowHidden ov_h { overflow: hidden; }
overflowScroll ov_s { overflow: scroll; }
overflowAuto ov_a { overflow: auto; }
overflowXVisible ovx_v { overflow-x: visible; }
overflowXHidden ovx_h { overflow-x: hidden; }
overflowXScroll ovx_s { overflow-x: scroll; }
overflowXAuto ovx_a { overflow-x: auto; }
overflowYVisible ovy_v { overflow-y: visible; }
overflowYHidden ovy_h { overflow-y: hidden; }
overflowYScroll ovy_s { overflow-y: scroll; }
overflowYAuto ovy_a { overflow-y: auto; }
List Style
Ruleset Key Default Classname Declarations
listStyleNone lis_n { list-style: none; }
listStylePositionInside lisp_i { list-style-position: inside; }
listStylePositionOutside lisp_o { list-style-position: outside; }
listStyleTypeNone list_n { list-style-type: none; }
listStyleTypeDisc list_d { list-style-type: disc; }
listStyleTypeCircle list_c { list-style-type: circle; }
listStyleTypeSquare list_s { list-style-type: square; }
listStyleTypeDecimal list_dc { list-style-type: decimal; }
listStyleTypeDecimalLeadingZero list_dclz { list-style-type: decimal-leading-zero; }
listStyleTypeLowerRoman list_lr { list-style-type: lower-roman; }
listStyleTypeUpperRoman list_ur { list-style-type: upper-roman; }
listStyleImageNone lisi_n { list-style-image: none; }

Classnames

Allows to overwrite any of the utility classnames:

module.exports = {
  classnames: {
    font: "font_$0",
    displayNone: "hidden",
    opacity0: "invisible"
  },
  ...
}

List of all available classnames can found here