JSFiddle - React, Tailwind, and code Playground

by rich_harris

HTML

<div id="todoapp" style="width:500px;margin:10px"></div>
<!-- Templates -->
		<script id="main" type="text/ractive">
			<header id="header">
				<h1>todos</h1>

				<!-- In app.js, we define a custom `enter` event, which fires when the user hits the enter key, submitting a new todo. -->
				<input id="new-todo" on-enter="newTodo" placeholder="What needs to be done?" autofocus>
			</header>

			<!--
			We only render the main section and the footer if we have one or more todos - in other words, `items.length` is not falsy.
			-->
			{{#items.length}}
				<section id="main">
					<!-- Here, we compare the total number of tasks (`items.length`) with the number of completed tasks (`completedTasks().length`). This calculation happens reactively, so we never need to manually trigger an update. When the `change` event fires on the input, the `toggleAll` event fires on the Ractive instance. -->
					<input twoway='false' id="toggle-all" type="checkbox" on-change="toggleAll" checked='{{ items.length === completedTasks().length }}'>
					<label for="toggle-all">Mark all as complete</label>

					<ul id="todo-list">
						{{#items:i}}
							<!-- The {{>item}} partial is defined in the script tag below -->
							{{>item}}
						{{/items}}
					</ul>
				</section>

				<footer id="footer">
					<span id="todo-count">
						<!-- The number of active tasks updates reactively -->
						<strong>{{ activeTasks().length }}</strong> {{ activeTasks().length === 1 ? 'item' : 'items' }} left
					</span>

					<ul id="filters">
						<li>
							<a class="{{ currentFilter === 'all' ? 'selected' : '' }}" href="#/">All</a>
						</li>
						<li>
							<a class="{{ currentFilter === 'active' ? 'selected' : '' }}" href="#/active">Active</a>
						</li>
						<li>
							<a class="{{ currentFilter === 'completed' ? 'selected' : '' }}" href="#/completed">Completed</a>
						</li>
					</ul>

					<!-- This section is only rendered if there are one or more completed tasks -->
					{{#...

JavaScript

(function (window, Ractive) {
	'use strict';

	// Create some filter functions, which we'll need later
	var filters = {
		completed: function (item) { return item.completed; },
		active: function (item) { return !item.completed; }
	};

	// The keycode for the 'enter' and 'escape' keys
	var ENTER_KEY = 13;
	var ESCAPE_KEY = 27;

	// Create our Ractive instance
	var todoList = new Ractive({
		// Specify a target element - an ID, a CSS selector, or the element itself
		el: 'todoapp',

		// Specify a template, or the ID of a script tag containing the template
		template: '#main',

		// This is our viewmodel - as well as our list of tasks (which gets added
		// later from localStorage - see persistence.js), it includes helper
		// functions and computed values
		data: {
			filter: function (item) {
				// Because we're doing `this.get('currentFilter')`, Ractive understands
				// that this function needs to be re-executed reactively when the value of
				// `currentFilter` changes
				var currentFilter = this.get('currentFilter');

				if (currentFilter === 'all') {
					return true;
				}

				return filters[currentFilter](item);
			},

			// completedTasks() and activeTasks() are computed values, that will update
			// our app view reactively whenever `items` changes (including changes to
			// child properties like `items[1].completed`)
			completedTasks: function () {
				return this.get('items').filter(filters.completed);
			},

			activeTasks: function () {
				return this.get('items').filter(filters.active);
			},

			// By default, show all tasks. This value changes when the route changes
			// (see routes.js)
			currentFilter: 'all'
		},

		// We can define custom events. Here, we're defining an `enter` event,
		// and an `escape` event, which fire when the user hits those keys while
		// an input is focused:
		//
		// <input id="edit" class="edit" on-blur-enter="submit" on-escape="cancel" autofocus>
		events: (function () {
			var makeCustomEvent = function...