{"id":16350468,"url":"https://github.com/zspecza/system","last_synced_at":"2025-07-28T23:38:10.840Z","repository":{"id":57328570,"uuid":"37467091","full_name":"zspecza/system","owner":"zspecza","description":"A component system syntax for CSS","archived":false,"fork":false,"pushed_at":"2016-11-09T08:39:25.000Z","size":29,"stargazers_count":11,"open_issues_count":5,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-15T02:39:21.700Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zspecza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-15T13:34:33.000Z","updated_at":"2022-12-17T21:02:53.000Z","dependencies_parsed_at":"2022-09-21T01:52:10.785Z","dependency_job_id":null,"html_url":"https://github.com/zspecza/system","commit_stats":null,"previous_names":["declandewet/system"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/zspecza/system","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zspecza%2Fsystem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zspecza%2Fsystem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zspecza%2Fsystem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zspecza%2Fsystem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zspecza","download_url":"https://codeload.github.com/zspecza/system/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zspecza%2Fsystem/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267604647,"owners_count":24114546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T01:05:07.140Z","updated_at":"2025-07-28T23:38:10.822Z","avatar_url":"https://github.com/zspecza.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/declandewet/system.svg?branch=master)](https://travis-ci.org/declandewet/system)\n[![NPM version](https://badge.fury.io/js/postcss-system.svg)](http://badge.fury.io/js/postcss-system)\n[![Dependency Status](https://david-dm.org/declandewet/system.svg)](https://david-dm.org/declandewet/system)\n[![devDependency Status](https://david-dm.org/declandewet/system/dev-status.svg)](https://david-dm.org/declandewet/system#info=devDependencies)\n[![Coverage Status](https://coveralls.io/repos/declandewet/system/badge.png?branch=master)](https://coveralls.io/r/declandewet/system)\n\nsystem\n=========\n\n[![Join the chat at https://gitter.im/declandewet/system](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/declandewet/system?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n\u003e **please note**, this module is in its early development phase and will likely change frequently.\n\n`system` is a [PostCSS](//github.com/postcss/postcss) plugin developed at [io](http://io.co.za) that allows you to augment your CSS with a syntax that aids in creating BEM-compliant front-end components and reads like a class definition.\n\n`system` essentially transforms this...\n\n```stylus\ncomponent(tweet) has(profile) {\n  border: 1px solid #eee;\n}\ncomponent(tweet) when(featured) has(profile) {\n  border-color: yellow;\n}\n```\n\n...into this:\n\n```css\n.tweet--profile {\n  border: 1px solid #eee;\n}\n.tweet.\\+featured .tweet--profile {\n  border-color: yellow;\n}\n```\n\nCombined with [postcss-nested](//github.com/postcss/postcss-nested) (which is loaded **before** `system`), the syntax looks something like this:\n\n```stylus\ncomponent(tweet) {\n  has(profile) {\n    border: 1px solid #eee;\n  }\n  when(featured) {\n    has(profile) {\n      border-color: yellow;\n    }\n  }\n}\n``` \n\nFor more features, check out the [API](#system-api). \n\n## Inspiration \u0026 Credit\n\nThis is inspired by, and very similar to another library called [CSStyle](//github.com/geddski/csstyle) by [Dave Geddes](https://github.com/geddski).\n\nFurther inspiration comes from wanting to use BEM without sacrificing the power of the cascade, which BEM supplements, rather than augments. Following the `system` syntax will ensure that you never have to worry about using `!important` or loading your components in any specific order, as long as your\ntop-most document element (e.g. `body`) has an `id` attribute of `system`.\n\n\u003e**Why re-invent the wheel?**\n\u003eWe needed a completely customisable version of CSStyle that could be used from any preprocessor *and* shares a single code base, because some of our developers have varying toolsets, and we also have ideas that will eventually deviate system from being too similar to CSStyle. Right now, `system` already supports multiple arguments, two extra methods ([`container`](#containerargs) for setting styles directly on a container, and [`is`](#isargs) for setting element state), the ability to output [mixins](#mixins-api) for all 3 major preprocessors that transform to the required PostCSS syntax and is so customizable you can even [**change the API**](#options).\n\n# Installation\n\n`system` can be installed with [npm](http://npmjs.org), which comes pre-installed with [Node.js](http://nodejs.org)\n\n```sh\n$ npm install postcss-system --save-dev\n```\n\n# Usage\n\n`system` is supported anywhere PostCSS is supported. This means you can use it from Gulp, Grunt, plain JavaScript, etc.\n\n```js\nvar postcss = require('postcss');\nvar system = require('postcss-system');\nvar nested = require('postcss-nested');\n\npostcss([nested, system.postcss/*([options={}])*/]);\n```\n\n## JavaScript API\n\n### `system.postcss([settings:Object])`\n\nThis method registers `system` as a PostCSS plugin, and is responsible for transforming your CSS. Typically, you would pass this method to your PostCSS plugin pipeline, after `postcss-nested` (that is, if you're using `postcss-nested`), either as a plain function reference (`system.postcss`) or a function call (`system.postcss()`).\n\nIt accepts an optional `settings` object. For more info, check out [Options](#options).\n\nExample:\n\n```js\npostcss([system.postcss({root: '#root'})]);\n```\n\n### `system.mixins(settings:Object)`\n\nThis method accepts a compulsory `settings` object, this is the same object one might pass to `system.postcss`, however `settings.preprocessor.output` and `settings.preprocessor.engine` are required in order for this to work. Check out [Options](#options) for more details.\n\nGiven the correct details, it will output a mixins file for your chosen CSS preprocessor `engine` to the `output` path, that you can then `@import` and use to compile down to PostCSS syntax. This method is only useful if you have a CSS build task that involves piping preprocessor output to PostCSS.\n\nBe sure to call this before `system.postcss`. Any settings passed to this method will be inherited by `system.postcss`.\n\nIt also returns a promise.\n\nExample:\n\n```js\nsystem.mixins({\n  preprocessor: {\n    engine: 'stylus',\n    output: path.join(__dirname, 'assets', 'styles')\n  }\n});\n```\n\nThen, at the top of your main Stylus file:\n\n```stylus\n@import 'system'\n```\n\nThis works for `sass`, `scss` and `less` too.\n\n## Options\n\nHere are the default options for `system`:\n\n```js\n{\n      preprocessor: {\n        output    : '.', // the output path for the system mixins file\n        engine    : null, // what css preprocessor you're using\n        namespace : '', // a namespace to prepend to each method\n        filename  : 'system' // the name of the mixins file\n      },\n      root: '#system', // the ID attribute for the root node\n      mixins: { // yes, you can customise the names of each method\n        block    : 'component',\n        element  : 'has',\n        modifier : 'when',\n        state    : 'is',\n        context  : 'inside',\n        util     : 'util',\n        parent   : 'container'\n      },\n      prefixes: { // and choose your own prefixes\n        block    : '.',\n        element  : '--',\n        modifier : '.\\\\+',\n        state    : ':',\n        context  : '.\\\\@',\n        util     : '.\\\\~',\n        parent   : '.\\\\@'\n      },\n      suffixes: { // and suffixes\n        block    : '',\n        element  : '',\n        modifier : '',\n        state    : '',\n        context  : '',\n        util     : '',\n        parent   : ''\n      },\n      extensions: { // what file extension to use for your mixins file\n        sass   : 'sass',\n        scss   : 'scss',\n        stylus : 'styl',\n        less   : 'less'\n      },\n      protectedStates: [ // these are not transformed by the `state` method\n        'enabled',\n        'disabled',\n        'checked',\n        'required',\n        'visited'\n      ]\n    }\n```\n\n## System API\n\n### `component(args...)`\n\nCreates a component.\n\n```stylus\ncomponent(tweet) {\n  color: blue;\n}\n```\n\n```css\n.tweet {\n  color: blue\n}\n```\n\n```html\n\u003cdiv class=\"tweet\"\u003e...\u003c/div\u003e\n```\n\n### `has(args...)`\n\nA `component` block `has` an element. An element sometimes also `has` an element.\n\n```stylus\ncomponent(tweet) {\n  has(avatar) {\n    border-radius: 50%;\n    has(edit-icon) {\n      background: url('wrench.png');\n    }\n  }\n}\n```\n\n```css\n.tweet--avatar {\n  border-radius: 50%;\n}\n.tweet--avatar--edit-icon {\n  background: url('wrench.png');\n}\n```\n\n```html\n\u003cdiv class=\"tweet\"\u003e\n  \u003cdiv class=\"tweet--avatar\"\u003e\n    \u003ci class=\"tweet--avatar--edit-icon\" /\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n### `when(args...)`\n\n`when` a block or element is modified, it's styles are overriden. An element can also react to it's parent block's modifier.\n\n```stylus\ncomponent(tweet) {\n  color: blue;\n  when(featured) {\n    color: yellow;\n    has(avatar) {\n      border: 1px solid yellow;\n    }\n  }\n  has(avatar) {\n    border-radius: 0;\n    when(circular) {\n      border-radius: 50%;\n    }\n  }\n}\n```\n\n```css\n.tweet {\n  color: blue;\n}\n.tweet.\\+featured {\n  color: yellow;\n}\n.tweet.\\+featured .tweet--avatar {\n  border: 1px solid yellow;\n}\n.tweet--avatar {\n  border-radius: 0;\n}\n.tweet--avatar.\\+circular {\n  border-radius: 50%;\n}\n```\n\n```html\n\u003cdiv class=\"+featured tweet\"\u003e\n  \u003cdiv class=\"+circular tweet--avatar\"\u003e...\u003c/div\u003e\n\u003c/div\u003e\n```\n\n### `is(args...)`\n\nWhen a component, container, or element `is` in a particular state, it receives new styles.\n\n```stylus\ncomponent(tweet) {\n  is(hovered, focused) {\n    transform: scale(1.1);\n  }\n  has(avatar) {\n    is(visited) {\n      opacity: 0.8;\n    }\n  }\n}\ncontainer(testimonials) {\n  is(hovered) {\n    background: purple;\n  }\n}\n```\n\n```css\n.tweet:hover,\n.tweet:focus {\n  transform: scale(1.1);\n}\n.tweet--avatar:visited {\n  opacity: 0.8;\n}\n.\\@testimonials:hover {\n  background: purple;\n}\n```\n\n### `container(args...)`\n\nCreates a parent. This is useful if you follow the OOCSS principle of separating content from container.\n\n```stylus\ncontainer(about-us) {\n  background: blue;\n}\n```\n\n```css\n.\\@about-us {\n  background: blue;\n}\n```\n\n```html\n\u003cdiv class=\"@about-us\"\u003e...\u003c/div\u003e\n```\n\n### `inside(args...)`\n\nIf a component is `inside` a container, you might choose to override specific properties.\n\n```stylus\ncomponent(tweet) {\n  background: white;\n  inside(testimonials) {\n    background: transparent;\n    color: #fff;\n  }\n}\n```\n\n```css\n.tweet {\n  background: white;\n}\n#system .\\@testimonials .tweet {\n  background: transparent;\n  color: #fff;\n}\n```\n\n```html\n\u003cdiv class=\"@testimonials\"\u003e\n  \u003cdiv class=\"tweet\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\n### `util(args...)`\n\nCreates a utility. These are generic and pretty specific - they will override everything with the exception of a component that is `inside` a container.\n\n```stylus\nutil(mt-10) {\n  margin-top: 10px;\n}\n```\n\n```css\n.\\~mt-10 {\n  margin-top: 10px;\n}\n```\n\n```html\n\u003cdiv class=\"tweet ~mt-10\"\u003e...\u003c/div\u003e\n```\n\n## Mixins API\n\nAll mixins follow the same method signature.\n\n\u003e**Please Note** that these mixins will only compile down to the syntax that is transformed by `system` through PostCSS, they are not to be used as standalone alternatives.\n\n### Stylus\n\n```stylus\n+component(tweet, box)\n  color: blue\n```\n\n### SCSS\n\n```scss\n@include component(tweet, box) {\n  color: blue;\n}\n```\n\n### SASS\n\n```sass\n+component(tweet, box)\n  color: blue\n```\n\n### LESS\n\n```less\n.component('tweet, box', {\n  color: blue;\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzspecza%2Fsystem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzspecza%2Fsystem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzspecza%2Fsystem/lists"}