CSS in JSで作るStyled Componentsの最小デザイン

CSS in JSでStyled ComponentsをAngularやReactといったフレームワークなしで作る最小デザインを例示する。

次のようなHTMLで表されるDOM ComponentにCSSを適用したいとする。

<article id="id">
  <h1>Title</h1>
  <ul>
    <li>item</li>
    <li>item</li>
  </ul>
</article>

単純にidで絞り込んだCSSを記述したstyle要素があればCSSを不足なく利用できる。

<article id="id">
  <style>#id ul { width: 100px; }</style>
  <h1>Title</h1>
  <ul>
    <li>item</li>
    <li>item</li>
  </ul>
</article>

このHTML(DOM Component)を生成する方法は次のように考えられる。

import TypedHTML from 'typed-dom';

const component = TypedHTML.article({ id: 'id' }, {
  style: TypedHTML.style(`#id ul { width: 100px; }`),
  title: TypedHTML.h1(`title`),
  content: TypedHTML.ul([
    TypedHTML.li(`item`),
    TypedHTML.li(`item`),
  ])
});

idを自動で埋め込めるようにするとミスを防ぐことができ、モジュラリティも得られる。

import TypedHTML from 'typed-dom';

const component = TypedHTML.article({ id: 'id' }, {
  style: TypedHTML.style(`$scope ul { width: 100px; }`),
  title: TypedHTML.h1(`title`),
  content: TypedHTML.ul([
    TypedHTML.li(`item`),
    TypedHTML.li(`item`),
  ])
});

固定idの直接指定は次のように

class Component {
  constructor(private readonly parent: HTMLElement) {
    this.parent.appendChild(this.element);
  }
  private readonly element = TypedHTML.div({ id: 'id' }, [
    TypedHTML.style(`$scope { position: relative; }`)
  ]).element;
  private readonly children = Object.freeze({
    list: new MicroComponent(this.element)
  });
  destroy() {
    this.element.remove();
  }
}

一時idの生成は次のように行える。

class MicroComponent {
  constructor(private readonly parent: HTMLElement) {
    this.parent.appendChild(this.dom.element);
  }
  private readonly dom = TypedHTML.div({ id: `${this.parent.id}-list-${Date.now()}-${Math.random() * 1e9 | 0}` }, {
    style: TypedHTML.style(`$scope ul { width: 100px; }`),
    content: TypedHTML.ul([
      TypedHTML.li(`item`)
    ])
  });
}

以上のようにCSS in JSでStyled Componentsを作るには単にscopeを作る要素を指定するセレクタの埋め込みとCSSを定義するstyle要素の同梱の2機能さえあれば最小構成として十分であり、面倒なフレームワークに抱き合わせられずに簡単に導入できる。

github.com

なおこのライブラリは以下のようにDOM構造の静的型を生成し内部構造を可視化、開発支援するものであり、付属機能としてCSS in JSをサポートしている。

TypedHTMLElement<"article", HTMLElement, {
  style: TypedHTMLElement<"style", HTMLStyleElement, string>;
  title: TypedHTMLElement<"h1", HTMLHeadingElement, string>;
  content: TypedHTMLElement<"ul", HTMLUListElement, TypedHTMLElement<"li", HTMLLIElement, string>[]>;
}>;