We think it’s generally necessary to use
  some sort of framework to develop web components,
  but that framework may not have to be monolithic in nature. Instead, the
  framework might be built entirely as mixins on top of a kernel that enables
  mixin composition.
  Rather than invoking a framework’s class constructor, one would simply
  compose the desired mixins together to create an instantiable web component.
  We’ve been prototyping a completely mixin-oriented approach to component
  development in a project called
  core-component-mixins.
  - 
    This relies on the
    Composable
    facility as the kernel to compose mixins in JavaScript. An alternative mixin
    strategy could be used as long it retained the same general degree of
    expressiveness. It would be ideal if multiple web component frameworks could
    agree on a mixin architecture so that we could share some of these mixins.
    We’d be happy to use a different mixin strategy in order to
    collaborate with more people.
  
- 
    The repo’s /src folder shows a core set of component mixins for
    template stamping, basic attribute marshaling, and Polymer-style automatic
    node finding. For example, the TemplateStamping mixin will add a
    createdCallback that creates a shadow root and clones into it the value of
    the component's template property:
    
import TemplateStamping from 'core-component-mixins/src/TemplateStamping';
class MyElement extends Composable.compose(HTMLElement, TemplateStamping) {
  get template() {
    return `
      <style>
      :host {
        font-weight: bold;
      }
      </style>
      Hello, world.
    `;
  }
}
    Use of the TemplateStamping mixin takes care of details like shimming any<style>elements found in the template when running under
    the Shadow DOM polyfill.
- 
    That /src folder contains a sample ReactiveElement base class that pre-mixes the
    three core mixins mentioned above to create a reasonable starting point for
    custom elements. The above example becomes:
    
import ReactiveElement from 'core-component-mixins/src/ReactiveElement';
class MyElement extends ReactiveElement {
  get template() {
    return `
      <style>
      :host {
        font-weight: bold;
      }
      </style>
      Hello, world.
    `;
  }
}
    Use of the ReactiveElement class is entirely optional
    — you could just as easily create your own base class using the same
    mixins.
- 
    The /demo folder shows some examples of components created with this
    mixin-based framework. such as
    Hello World
    example.
  
- 
    A demo of a
    hypothetical X-Tag implementation
    shows how a framework can use mixins to create its own custom
    element base class. In that demo, the hypothetical framework adds support
    for a mixin that provides X-Tag’s “events” sugar, but
    leaves out the mixin for automatic node finding. The point is that
    frameworks and apps can opt in to the component features they want.
  
- 
    In this approach, web component class definition is generally kept separate
    from custom element registration. That is, there’s no required entry
    point like Polymer() to both create the class and register it in a single
    step. We personally feel that keeping those two steps separate makes each
    step clearer, but that’s a matter of taste. If you feel that combining
    those steps makes your code easier to write or read, it’s easy enough
    to accomplish that. The X-Tag demo shows how a framework could define an
    entry point for class definition and registration.
  
- 
    The mixin architecture explicitly supports custom rules for composing
    specific properties. That’s intended for cases like the
    “properties” key in Polymer behaviors, where object values
    supplied by multiple mixins need to get merged together. The Composable
    kernel supports that, although none of the demos currently show off that
    feature.
  
  Taken collectively, these core component mixins form the beginnings of a
  deliberately loose but useful framework for web component development.
  They’re still rudimentary, but they already provide much of
  what we need from a layer like polymer-micro.
  We think this strategy confers a number of advantages:
  - 
    This is closer to the metal.
    The only new thing here is the concept of a mixin. Everything else is part
    of the web platform. There’s no special class constructor required to
    perform black-box operations on a component. There’s nothing new to
    master (like React’s JSX or Polymer’s <dom-element>)
    that’s not already in the platform. There's no sugaring provided out
    of the box — and that’s a good thing.
  
- 
    Each mixin can focus on doing a single task really well.
    For example, the TemplateStamping mixin just creates a shadow root and
    stamps a template into it. The only real work it’s doing is to
    normalize the use of native vs polyfilled Shadow DOM — that is,
    the work you’d need to do anyway to work on all browsers today. Given
    the boilerplate nature of that task, it’s reasonable to share that
    code with a mixin like this. Once all the browsers support Shadow DOM v1
    natively, this mixin could be simplified, or dropped entirely, without
    needing to rearchitect everything.
  
- 
    You can stay as close to/far from the platform as you want.
    Most user interface frameworks take you far away from the platform in one
    giant step. Here you have fine-grained control over each step you take
    toward a higher level of abstraction. Each mixin takes you a tiny bit
    further away from the platform, and in exchange for the efficiency boost the
    mixin provides, you have to accept some trade-offs: performance, mystery,
    etc. That’s an unavoidable price for sharing code, but at least this
    way you can decide how much you want to pay.
  
- 
    There's a potential for cross-framework mixins.
    If multiple web component frameworks could agree on a mixin architecture,
    there’d at least be a chance we could share good solutions to common
    higher-level problems at the sub-component level. When Component Kitchen
    creates a mixin to support, say, accessibility in a list-like web component,
    it would be great if we could make that available to people developing
    list-like web components in other frameworks. While any framework could in
    theory adopt some other framework’s mixin format, mixins are usually
    intimately tied to a framework. Explicitly deciding to factor mixins into a
    separable concept may make cross-framework mixins more feasible.
  
  It’s worth remembering that web components are, by their very nature,
  interoperable. If you decide to write a component using an approach like this,
  it’s still available to someone who’s using a different framework
  (Polymer, say). The reverse is also true. That means any team can pick the
  approach that works for them, while still sharing user interface elements at
  the component level.
  As we’re experimenting with these mixin ideas in prototype form,
  we’re opportunistically trying some other technology choices at the same
  time:
  - 
    These mixins are written in ES6. As the polymer-micro blog post mentioned,
    we’re finding that ES6 makes certain things easy enough in JavaScript
    that we can use the DOM API directly, rather than relying on a framework for
    sugar. Transpiling with
    Babel
    feels like a fine temporary solution while waiting for native ES6
    implementations in all browsers.
  
- 
    While the core component mixins are written in ES6, they can still be used
    by plain ES5 apps. The
    Hello World (ES5)
    demo shows this in practice.
  
- 
    The TemplateStamping mixin assumes use of the Shadow DOM polyfill if you
    want to support browsers that don’t yet support Shadow DOM. If the
    majority of the world’s web users have a Shadow DOM v1-capable browser
    by, say, the second half of 2016, we think businesses might accept using the
    polyfill to support the shrinking number of users with older browsers. To
    the extent using that polyfill has issues, those issues should diminish over
    time.
  
- 
    We use JavaScript module imports as the dependency mechanism rather than
    HTML Imports. That lets us leverage tools like
    browserify
    for concatenation rather than Vulcanize. So far, that’s working okay.
    ES6 template strings let us easily embed HTML directly inside of JavaScript
    files, instead of putting JavaScript code inside of HTML files as we did
    with HTML Imports. Both packaging formats can work, but given the need for
    JavaScript modules anyway, it seems worthwhile for us to see what we can
    build with modules alone. One thing we miss: an equivalent of HTML
    Import's “document.currentScript” so that a module can load
    a resource from a path relative to the JavaScript source file.
  
- 
    We’re trying out npm as the primary means of component distribution.
    We think that npm 3’s support for dependency flattening addresses much
    of the need for Bower. We think the combination of ES6 modules and npm may
    prove to be a better way to distribute components, so we’re trying
    that out with this prototype to see if we could make the switch to dropping
    Bower entirely. So far, this feels very good.
  
  This mixin-based component framework isn’t done, but feels like
  it’s reached the point where it’s “good enough to
  criticize”. Please share your feedback at;
  @Component
  or
  +ComponentKitchen.
   
  « Blog home