diff --git a/examples/tags-todomvc/.gitignore b/examples/tags-todomvc/.gitignore
new file mode 100644
index 0000000..01a5e93
--- /dev/null
+++ b/examples/tags-todomvc/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+build
+*.log
diff --git a/examples/tags-todomvc/package.json b/examples/tags-todomvc/package.json
new file mode 100755
index 0000000..0a47750
--- /dev/null
+++ b/examples/tags-todomvc/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "tags-todomvc",
+ "description": "Marko TodoMVC example",
+ "version": "1.0.0",
+ "dependencies": {
+ "@marko/tags-api-preview": "^0",
+ "marko": "^5"
+ },
+ "devDependencies": {
+ "@marko/build": "^4",
+ "@marko/serve": "^4"
+ },
+ "private": true,
+ "scripts": {
+ "build": "marko-build ./src/pages",
+ "dev": "marko-serve ./src/pages",
+ "start": "node ./build/index.js"
+ }
+}
diff --git a/examples/tags-todomvc/src/components/todomvc-app/demo.marko b/examples/tags-todomvc/src/components/todomvc-app/demo.marko
new file mode 100755
index 0000000..ba3574a
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-app/demo.marko
@@ -0,0 +1,20 @@
+
+
+
diff --git a/examples/tags-todomvc/src/components/todomvc-app/index.marko b/examples/tags-todomvc/src/components/todomvc-app/index.marko
new file mode 100755
index 0000000..aa2428f
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-app/index.marko
@@ -0,0 +1,85 @@
+
+
+
+
+ {
+ if (todo.pending) return true;
+ if (filter === "active") return !todo.completed;
+ if (filter === "completed") return todo.completed;
+ return true;
+ })/>
+ todo.completed).length />
+ (e) => {
+ setFilter(filter);
+ e.preventDefault();
+ })/>
+
+
+
+
+
+ todo.id)>
+
+
+
+
+
+
+ ${remainingCount} ${remainingCount > 1 ? "items" : "item"} left
+
+
+
+
+ All
+
+
+
+
+ Active
+
+
+
+
+ Completed
+
+
+
+
+
+ Clear completed
+
+
+
+
+
+
+
diff --git a/examples/tags-todomvc/src/components/todomvc-header/demo.marko b/examples/tags-todomvc/src/components/todomvc-header/demo.marko
new file mode 100755
index 0000000..4cb06d4
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-header/demo.marko
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/examples/tags-todomvc/src/components/todomvc-header/index.marko b/examples/tags-todomvc/src/components/todomvc-header/index.marko
new file mode 100755
index 0000000..4196ca1
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-header/index.marko
@@ -0,0 +1,18 @@
+
+
+ todos
+
+
+
+
diff --git a/examples/tags-todomvc/src/components/todomvc-store/index.marko b/examples/tags-todomvc/src/components/todomvc-store/index.marko
new file mode 100644
index 0000000..3c8ccea
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-store/index.marko
@@ -0,0 +1,47 @@
+
+
+
+ {
+ if (todo.id !== todoId) return todo;
+ return { ...todo, ...newProps }
+ })
+ },
+ clearCompleted() {
+ todos = todos.filter(todo => !todo.completed);
+ },
+ removeTodo(todoId) {
+ todos = todos.filter(todo => todo.id !== todoId);
+ },
+ toggleAllTodosCompleted(completed) {
+ todos = todos.map((todo) => {
+ if (todo.completed === completed) return todo;
+ return { ...todo, completed };
+ });
+ },
+ addNewTodo(todoData) {
+ todos = [...todos, {
+ title: todoData.title,
+ id: 'c' + (nextId++),
+ completed: false
+ }];
+ }
+} />
\ No newline at end of file
diff --git a/examples/tags-todomvc/src/components/todomvc-todo-item/animations.js b/examples/tags-todomvc/src/components/todomvc-todo-item/animations.js
new file mode 100755
index 0000000..553b256
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-todo-item/animations.js
@@ -0,0 +1,28 @@
+export function animateOut(event, node) {
+ event.preventDefault();
+ node.classList.add("animate");
+ var height = node.offsetHeight;
+ node.style.maxHeight = height + "px";
+
+ setTimeout(() => {
+ node.style.maxHeight = "0px";
+ node.style.opacity = 0;
+
+ setTimeout(() => {
+ event.detach();
+ }, 250);
+ }, 0);
+}
+
+export function animateIn(event, node) {
+ var height = node.offsetHeight;
+ node.classList.remove("animate");
+ node.style.maxHeight = "0px";
+ node.style.opacity = 0;
+
+ setTimeout(() => {
+ node.classList.add("animate");
+ node.style.maxHeight = height + "px";
+ node.style.opacity = 1;
+ }, 10);
+}
diff --git a/examples/tags-todomvc/src/components/todomvc-todo-item/demo.marko b/examples/tags-todomvc/src/components/todomvc-todo-item/demo.marko
new file mode 100755
index 0000000..46a867a
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-todo-item/demo.marko
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/examples/tags-todomvc/src/components/todomvc-todo-item/index.marko b/examples/tags-todomvc/src/components/todomvc-todo-item/index.marko
new file mode 100755
index 0000000..63982c0
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-todo-item/index.marko
@@ -0,0 +1,55 @@
+import { animateIn, animateOut } from "./animations";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/tags-todomvc/src/components/todomvc-todo-item/style.css b/examples/tags-todomvc/src/components/todomvc-todo-item/style.css
new file mode 100755
index 0000000..79d0f94
--- /dev/null
+++ b/examples/tags-todomvc/src/components/todomvc-todo-item/style.css
@@ -0,0 +1,17 @@
+.todo-list li.pending .toggle, .todo-list li.pending button {
+ visibility: hidden;
+}
+
+.todo-list li.pending label {
+ color: #d9d9d9;
+}
+
+.todo-list li {
+ opacity: 1;
+ background-color: #fff;
+ overflow: hidden;
+}
+
+.todo-list li.animate {
+ transition: opacity 250ms ease-in-out, max-height 250ms ease-in-out;
+}
diff --git a/examples/tags-todomvc/src/pages/index.marko b/examples/tags-todomvc/src/pages/index.marko
new file mode 100755
index 0000000..f522bec
--- /dev/null
+++ b/examples/tags-todomvc/src/pages/index.marko
@@ -0,0 +1,8 @@
+
+
+ Marko | TodoMVC
+
+
+
+
+