DEV Community

Nick Taylor
Nick Taylor

Posted on • Updated on • Originally published at iamdeveloper.com

scoped-style

GitHub logo sadick254 / scoped-style

A tiny css in js library 🚀

Scoped Style

Scoped style is a next gen tiny css-in-js library to help you style your components. Use the full power of css that you are used to.

Works With

Installation

npm i scoped-style
// or
yarn add scoped-style
Enter fullscreen mode Exit fullscreen mode

Usage

import scoped from 'scoped-style';
// for react
import React from 'react';
const styled = scoped(React.createElement);
//

// for Preact
import { h } from 'preact';
const styled = scoped(h);
//

// for Hyperapp
import { h } from 'hyperapp';
const styled = scoped(h);
//

// for Infernojs
import { createElement } from 'inferno-create-element';
const styled = scoped(createElement);
//

// define global css
styled.global`
  * {
    margin: 0;
  }

  html,
  body {
    width: 100%;
    height: 100%;
  }
`;

// and
…
Enter fullscreen mode Exit fullscreen mode

A new kid on the CSS in JS block.

Plays nicely with Preact, React, Hyperapp and InfernoJS.

An example from the readme for React:

import React from "react"
import scoped from "scoped-style"

const styled = scoped(React.createElement)


// define global css
styled.global`
  * {
    margin: 0;
  }

  html,
  body {
    width: 100%;
    height: 100%;
  }
`;

// and scoped css
const Button = styled("button")`
  background: ${props => props.primary ? "orange": "gray"};
  border: none;
  border-radius: 2px;
  :hover {
    padding: 10px;
  }
`

const App = () => (
  <div>
    <Button primary>Login</Button>
  </div>
)

// Your rendering code

Enter fullscreen mode Exit fullscreen mode

Top comments (10)

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited

For those that want to do this kind of thing without JS overhead, there's a browser standard for this called Shadow DOM.

const shadowRoot = el.attachShadow({mode: "open"});
shadowRoot.appendChild(someDom);

el.querySelector('.some-scoped-class'); // null
el.shadowRoot.querySelector('.some-scoped-class'); // child of someDom

You can either roll your own with the bare DOM APIs as above or use a lightweight templating and component library like LitElement or Hybrids.

Read all about it:

Collapse
 
nickytonline profile image
Nick Taylor • Edited

But that's only if you're using web components right? Also, is the shadow DOM implemented in all the main browsers now? Last time I checked, which has been a while, it was only implemented in Chrome.

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited

It's if you're using the web. attachShadow is a method on HTMLElement. You can attach a shadow root to any div.

So really, the caveat belongs on the library: "if you are not using the actual DOM, you will need to use JavaScript to scope your styles". If you are invested in react, for example, and you want to benefit from the new standard, you'll either have to wait until the react authors ingest the standard, or find a workaround. (I'm not an expert on react so feel free to correct me on this)

ShadowDOM is supported by all major browsers except Edge, which will get it for free in the next version, and there is a polyfill for old or unsupporting browsers.

Thread Thread
 
nickytonline profile image
Nick Taylor • Edited

For those that have never heard of what you're taking about, I'm assuming the polyfill you're referring to is the Polymer Project?

Alright, so getting back to it, to be clear, I can only use scoped styles within a template element correct?And a template element can only be used within a custom element right? So getting back to my orignal question, scoped styles in the browser can only be used within a web component right?

To be clear, I'm not knocking web components, I just want to make sure my understanding is correct because even the MDN docs example for attachShadow use a web component as an example.

Thread Thread
 
nickytonline profile image
Nick Taylor

In terms of React, there's no reason you can't use a web component (WC) in a React component. At the end of the day it's just a DOM element. I mean like you said, <video /> tag is a WC (in at least Chromium based browsers) and people use those in React components. So in that respect a WC is raw building block, like a <div />.

For the rest of this, I'll just leave this comment from @dan_abramov as it's a good read and a related Tweet thread.

A few quick points from my perspective. (I work on React.)

  1. We're not opposed to supporting web components better. The problem is that there's no single "web component community". There are multiple subcommunities. You mention "web component libraries" in the post. These libraries don't agree on a single standard so React would need to pick a side in debates like "how does server rendering work with web components". Whatever we pick will have large downstream effects, and our reluctance to support more has to do with being careful (see [1] note below) about the semantics — not somehow being at odds with web components per se.

  2. As I mentioned in the previous point (and you mentioned in the post), there are multiple "web component libraries". As far as I can see many of the criticisms of React would apply to such libraries as well. I don't think the way to counteract "DOM FUD" is to introduce "library FUD". If you're using a library for defining and updating your web components declaratively, you're not following a conceptually different approach from using React.

  3. Saying "you can do everything with WCs that you can do in React" is double edged. Yes, of course, you can do anything — because we haven't actually agreed upon any constraints. If the constraint is "you don't use a React-like library on top" I think you'll find there's plenty of things that are very hard to do with an imperative abstraction like vanilla WC APIs. We've done a few talks about what using React as a unifying abstraction lets us do (such as non-blocking rendering, or dynamically loading UI code without degrading user experience). You might want to check them out (youtube.com/watch?v=nLF0n9SACd4, youtube.com/watch?v=ByBPyMBTzM0). Of course, you can do these things if you use a library like React on top of WCs. But that negates the argument that you don't need React-like libraries for this.

To sum up: we'd be happy to support WCs better in React. We don't want to rush it, and want to make sure this support is well thought-out. Additionally, we believe there are many things that raw imperative WC APIs don't give you — and for them something like React would be appropriate even in a WC world. Finally, there's this myth going around that once you write React code, you can't reuse it as web components. That's not true — and as you can see from the documentation it's a few lines of code: reactjs.org/docs/web-components.ht...

Hope that makes sense, and provides some additional context!

[1]: For example, if I'm not mistaken, the semantics chosen by Preact make introducing a new standard property to DOM base element potentially a breaking change for the web. We try to avoid such problems if possible — precisely because React did learn from MooTools and we don't want to do another mistake like what happened with Array.prototype.flatten().

Thread Thread
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦 • Edited

Good questions. Nothing you're asking here comes off as a knock. It's really nice for me to see developers who might not have heard much about these powerful new standards engaging with them.

Polymer? Web Components? Polyfill?

Polymer Project is the Google team which initially proposed the new standards and shepherded them through the standards process. They also wrote and maintained the polymer library, which is a specific implementation of web components.

Five years ago, the only way to polyfill the standards was with the polymer library. Today, you can npm i -S @webcomponents/webcomponentsjs to get the polyfills - no need to include polymer.

So point No. 1: you don't need to (and even probably shouldn't) use Polymer library to make web components. Also, now that the standards are established and implemented, it's not like Google can just cancel them like inbox or hangouts.

But isn't Shadow DOM for Web Components only?

Now, Shadow DOM is only one of the four standards that we collectively refer to as "web components". It's very likely that you'll most often want to attach a shadow root to a custom element in it's constructor (or via a library that does same), but you don't have to. <input> has a shadow root. So does <video>. You don't have to use custom elements to use Shadow DOM.

It's also likely you'll want to use the template element to stamp DOM into that shadow root (or use a library that does same), since it's way faster than innerHTML, but you don't have to use template to use Shadow DOM. You can just attach a shadow root to some div then append existing DOM to it, if you want. You could also render your react app into that shadow root if you wanted. (Although, for half the ticket price, you might as well just use custom elements in such a case)

So the web components standards work well together, but don't require one another.

Collapse
 
nickytonline profile image
Nick Taylor

From what I can tell, the API is very similar, if not identical to styled components' API aside from setting global styles.

Collapse
 
ben profile image
Ben Halpern

Why might someone choose this over Style Components?

Collapse
 
nickytonline profile image
Nick Taylor

Gonna have to test it out and get back to you. Initial thought though is bundle size and perhaps more compatability with React inspired/React like libraries. I came across this library because I follow @_developit on GitHub and he starred it. Any other reasons why you'd prefer this over another CSS in JS framework Jason?

Thread Thread
 
_developit profile image
Jason Miller 🦊⚛

I actually don't use CSS-in-JS much (mainly just because I'm a creature of habit), but I liked the way they made global styles easy and thought the parser looked decent.