WebComponents, Yo! (WCYO)

This page contains my first attempts to use Yo-Yo with Web Components. My goal is to create something that's as easy-to-use as React, but that's much more minimal and native.

page repo


hello-label

window.customElements.define('hello-label', class extends HTMLYoYo {
  render() {
    return yo`<div>Hello ${this.getAttribute('label')}</div>`
  }
})
    


seconds-elapsed

window.customElements.define('seconds-elapsed', class extends HTMLYoYo {
  static get observedAttributes() {
    return ['tick']
  }

  connectedCallback() {
    this.state.tick = 0
    this.interval = setInterval(() => {
      this.state.tick++
    }, 1000)
  }

  disconnectedCallback() {
    clearInterval(this.interval)
  }

  render() {
    return yo`<div>Seconds Elapsed: ${this.getAttribute('tick')}</div>`
  }
})


todo-app

window.customElements.define('todo-app', class extends HTMLYoYo {
  constructor() {
    super()
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
    this.state.items = []
    this.state.text = ''
  }

  static get observedAttributes() {
    return ['items', 'text']
  }

  render() {
    return yo`
      <div>
        <h3>TODO</h3>
        <todo-list items=${this.getAttribute('items')}></todo-list>
        <form onsubmit=${this.handleSubmit}>
          <input onchange=${this.handleChange} value=${this.state.text} />
          <button>${'Add #' + (this.state.items.length + 1)}</button>
        </form>
      </div>
    `
  }

  handleChange(e) {
    this.state.text = e.target.value
  }

  handleSubmit(e) {
    e.preventDefault()
    var newItem = {
      text: this.state.text,
      id: Date.now()
    }
    this.state.items = this.state.items.concat([newItem])
    this.state.text = ''
  }
})

window.customElements.define('todo-list', class extends ThirdBase {
  constructor() {
    super()
  }

  static get observedAttributes() {
    return ['items']
  }

  render() {
    const items = this.state.items || []
    return yo`
      <ul>
        ${items.map(item => yo`
          <li key=${item.id}>${item.text}</li>
        `)}
      </ul>
    `
  }
})

markdown-editor

window.customElements.define('markdown-editor', class extends HTMLYoYo {
  constructor() {
    super()
    this.handleChange = this.handleChange.bind(this);
    this.state.value = 'Type some *markdown* here!'
  }

  static get observedAttributes() {
    return ['value']
  }

  handleChange(e) {
    this.state.value = e.target.value
  }

  getRawMarkup() {
    var md = new Remarkable()
    return md.render(this.state.value)
  }

  render() {
    var el = yo`
      <div class="markdown-editor">
        <h3>Input</h3>
        <textarea onchange=${this.handleChange}>${this.state.value}</textarea>
        <h3>Output</h3>
        <div class="content"></textarea>
      </div>
    `
    el.querySelector('.content').innerHTML = this.getRawMarkup()
    return el
  }
})