An Ember CLI addon which allows you to specify styles for individual components
JavaScript HTML CSS
Clone or download
Latest commit 242af80 Jun 20, 2018
Permalink
Failed to load latest commit information.
addon fix(ember inspector): Mixins created with an empty create breaks embe… Feb 26, 2018
app fix(module imports): moved functionality that belonged to just the a… Feb 6, 2018
bin Upgraded packages and fixed tests. (#264) Jan 26, 2018
config chore(ember cli upgrade): running ember init to updated packages to n… Feb 23, 2018
lib fix(component name parsing): only switching out the word 'compoent/' … Jul 31, 2017
tests lint(strict): added a strict to the dummy's config to take the update… Feb 23, 2018
.bowerrc Initial Commit from Ember CLI v0.2.0-beta.1 Mar 3, 2015
.editorconfig updated ember cli to latest version, removed old tests, and added in … Jul 13, 2016
.ember-cli updated ember cli to latest version, removed old tests, and added in … Jul 13, 2016
.eslintrc.js chore(ember cli upgrade): running ember init to updated packages to n… Feb 23, 2018
.gitignore chore(upgrade): upgraded ember cli and all dependecies to latest verson Jul 31, 2017
.npmignore Upgraded packages and fixed tests. (#264) Jan 26, 2018
.travis.yml chore(ember cli upgrade): running ember init to updated packages to n… Feb 23, 2018
.watchmanconfig Update ember-cli to 1.13.13 Jan 27, 2016
CHANGELOG.md chore(release): 0.6.4 Jun 20, 2018
LICENSE.md chore(package): udpated ember-cli to 3.11, and updated corresponding … Jan 25, 2017
README.md amendment Jun 20, 2018
ember-cli-build.js Upgraded packages and fixed tests. (#264) Jan 26, 2018
index.js amendment Jun 20, 2018
package.json chore(release): 0.6.4 Jun 20, 2018
testem.js Upgraded packages and fixed tests. (#264) Jan 26, 2018
yarn.lock spec(ember-try): adding in ember try as a dev dependency Feb 23, 2018

README.md

ember-component-css Build Status Ember Observer Score

An Ember CLI addon which allows you to specify component-specific style sheets in an app, addon, engine, or in-repo addon.

Contributions are welcome! Feel free to open up a pull request or issue, and join the #e-component-css channel in the Ember Slack community if you have further questions, concerns, or ideas. Thanks! 😄

Installation

ember install ember-component-css

Usage

Rules defined in the style-sheets will automatically be namespaced with an autogenerated class. That autogenerated class will also be injected into your component's classNames property. This enables you to worry less about rules clashing across component styles.

For example, given this app/my-component/styles.scss file for 'pods',

or this app/styles/component-styles/my-component.scss file for 'classic':

& {  // ampersand refers to the component itself (parent selector)
  padding: 2px;
}
.urgent {
  color: red;

  span {
    text-decoration: underline;
  }
}

Your generated CSS output will look something like:

.__my-component__a34fba {
  padding: 2px;
}
.__my-component__a34fba .urgent {
  color: red;
}
.__my-component__a34fba .urgent span {
  text-decoration: underline;
}

A typical component invocation that looks like this:

{{my-component}}

will generated markup like:

<div class="__my-component__a34fba"></div>

Inclusion

To use this addon you MUST, import pod-styles into your base stylesheet.

// app/styles/app.scss
@import "pod-styles";
// app/styles/app.less
@import "pod-styles";
// app/styles/app.styl
@import 'pod-styles'
/* app/styles/app.css */
@import "pod-styles.css";

And that is it! The pod-styles file is generated during the build and will then be pulled into your other stylesheet to be processed like normal.

Note: If you are using more than one type of component style files (ie a .less file and a .scss file) then you will need to add the extension to the @import. Otherwise the extension can be left off.

Usage with pods structure

To use this with pods, you just need to include a style file in your component pods directory alongside your template.hbs or component.js files.

Usage with routes

To use this with routes you need to use pods for the routes and modify the application.hbs template a little bit. Let's assume your application.hbs template looks like this:

{{outlet}}

To be able to use this for routes, you need to add a wrapping div around the outlet:

<div class={{routeStyleNamespaceClassSet}}>
  {{outlet}}
</div>

After that it's quite easy: add a style file in your route directory alongside your route.js or template.hbs files.

An individual controller also has access to a styleNamespace property that is the namespace for a given route. This can be used for various use cases. (like enabling BEM style similar to how the styleNamespace is used in a component)

Usage with classic (non pod) structure

You can use classic Ember app structure by placing component styles in app/styles/component-styles. Name your style files after the component name, for example my-component.scss. The directory where styles are fetched from can be configured as shown below. It's possible to use a mixture of classic and pod structured styles in the same app, if you use both styles for the same component both are included but the pod style will take precedence.

Use in addons

In order to use this inside of an addon, you need to add your style files inside of the components in the addon directory. You will then be able to import the 'pod-styles' file inside of your addon style file which is in the /addon/styles directory. These styles will then be added to the vendor.css file like normal.

If you are using classic (non pod) structure, your addon directory structure might look like:

yourAddonDirectory
│   index.js
│   ... etc
└───addon
│   └───components
│       │   yourAddonComponent.js
│   └───templates
│       │   yourAddonComponent.hbs
│   └───styles
│       │   addon.scss (includes the 'pod-styles' import)
│       └───component-styles (this dir name is configurable)
│           │   yourAddonComponent.scss
└───app
    └───components
        │   yourAddonComponent.js

If you are extending the include method in your addon, please make sure you call the super like this

  included: function(app) {
    this._super.included.apply(this, arguments);
    ...
  }

Finally, be sure "ember-component-css" is listed under the "dependencies" key of your addon's package.json file, rather than "devDependencies".

Plain css usage

In order to use this with plain css files, you need to install ember-cli-postcss and configure it with postcss-import.

ember install ember-component-css
ember install ember-cli-postcss
npm install postcss-import --save-dev

Then in your ember-cli-build.js you can configure it as such.

var EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
var CssImport = require('postcss-import');

module.exports = function(defaults) {
  var app = new EmberAddon(defaults, {
    postcssOptions: {
      compile: {
        enabled: true,
        plugins: [{
          module: CssImport,
        }]
      }
    }
  });

  return app.toTree();
};

You can also add in postcss-cssnext or any other postcss plugins in this way too.

Things like ember-cli-autoprefixer will work out of the box and do not need to be added in as a postcss plugin.

Getting the generated class name

You also have access to the generated class name to use in your templates. There is a computed property styleNamespace This can be used to pass the class name to things like ember-wormhole or for use in BEM style classnames. An example of BEM usage would be

my-component/template.hbs

<button class="{{styleNamespace}}__button">
  Normal button
</button>
<button class="{{styleNamespace}}__button {{styleNamespace}}__button--state-success">
	Success button
</button>
<button class="{{styleNamespace}}__button {{styleNamespace}}__button--state-danger">
	Danger button
</button>

my-component/styles.scss

&__button {
  display: inline-block;
  border-radius: 3px;
  padding: 7px 12px;
  border: 1px solid #D5D5D5;
  background-image: linear-gradient(#EEE, #DDD);
  font: 700 13px/18px Helvetica, arial;

  &--state-success {
    color: #FFF;
    background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
    border-color: #4A993E;
  }

  &--state-danger {
    color: #900;
  }
}

componentCssClassName will be officially deprecated, then removed in future versions. Will be migrating to the more appropriately named styleNamespace

Using the generated class name in classNameBindings

You can build your own computed properties on top of styleNamespace. One use case is using it to build a classNameBinding:

my-component/component.hbs

classNameBindings: ['customBinding'],
  stateProperty: false,
  customBinding: computed('styleNamespace', 'stateProperty', function() {
    if (this.get('stateProperty')) {
      return `${this.get('styleNamespace')}--state`;
    } else {
      return '';
    }
  }),

my-component/styles.scss

& {
  background: blue;
}
&--state {
  background: red;
}

Special Tag-less components

On the special cases of tag-less components (this functionality is used putting a tagName: '' value in the component), the styles are not attached to the DOM, as this addon needs a tag to attach the generated class name. In those special cases, you can use the styleNamespace* classname if you want to attach to a another element in the application (or more coherently inside the tag-less component).

Configuration

You can set the following configuration options in your config/environment.js file:

ENV['ember-component-css'] = {
  option: 'value'
}

namespacing(enabled)

Defaults to true. Set this option to false to disable the namespacing feature of Ember Component CSS.

ENV['ember-component-css'] = {
  namespacing: false
}

This changes the default behavior in two ways:

  1. The autogenerated component class is no longer added to your component's HTML
  2. Your pod CSS files are no longer namespaced using the autogenerated component class.

classicStyleDir

Defaults to component-styles. Set this to the directory where your classically structured styles live (within /app/styles). For example:

ENV['ember-component-css'] = {
  classicStyleDir: 'my-styles'
}

excludeFromManifest

Defaults to []. Set this option to one or more matcher expression (regular expression, glob string, or function). Style files matching the expresion(s) will be namespaced but not imported in the pod-styles manifest. You will need to import the matching style files manually in your CSS. This can be useful when you need to control the order in which specific style files need to be imported.

Example: You want to have a separate style file for each media-query breakpoint. You want to be sure that _style-1366.scss will be imported before _style-960.scss

.
└── my-component/
    ├── _style-1366.scss
    ├── _style-960.scss
    ├── main.scss
    ├── component.js
    └── template.hbs
// main.scss
@import "./_style-1366"
@import "./_style-960"
ENV['ember-component-css'] = {
  excludeFromManifest: ['**/_style-*']
}

The announcement from EmberConf 2015

CSS is hard - EmberConf 2015