DEV Community

Cover image for SolidJS and Tailwindcss Todo App
Harsh Mangalam
Harsh Mangalam

Posted on

4 1

SolidJS and Tailwindcss Todo App

Solidjs is a new Javascript Framework which introduce the clear concept of fine-grained reactivity system.

Every Component executes once and it is the Hooks and bindings that execute many times as their dependencies update.

In this post i will show how we can combine tailwindcss and solidjs to create simple todo.

For icons i have used heroicons

Todo App

Todo App

create new solid js application using vite



npx degit solidjs/templates/js todo

cd todo

pnpm i



Enter fullscreen mode Exit fullscreen mode

setup tailwindcss



npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

npx tailwindcss init




Enter fullscreen mode Exit fullscreen mode

src/styles/index.css




@tailwind base;
@tailwind components;
@tailwind utilities;



Enter fullscreen mode Exit fullscreen mode

tailwind.config.js




const { rule } = require("postcss");

module.exports = {
  purge: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  darkMode: false, // or 'media' or 'class',
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
};




Enter fullscreen mode Exit fullscreen mode

src/index.jsx




import { render } from "solid-js/web";

import "./styles/index.css";
import App from "./App";

render(App, document.getElementById("root"));





Enter fullscreen mode Exit fullscreen mode

src/components/Button.jsx




function Button(props) {
  return (
    <button
      onClick={props.onClick}
      class={`bg-${props.bg}-500 text-${props.bg}-50 hover:bg-${props.bg}-700 focus:outline-none focus:ring-2 focus:ring-${props.bg}-600 focus:ring-opacity-50 px-1 py-1 md:px-4 md:py-2 rounded-lg ${props.class}`}
    >
      {props.children}
    </button>
  );
}

export default Button;



Enter fullscreen mode Exit fullscreen mode

src/components/InputField.jsx




function InputField(props) {
  return (
    <input
      type="text"
      class={`border-2 border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-600 px-1 py-1  md:px-2 md:py-2 rounded-lg ${props.class}`}
      onInput={props.onInput}
      value={props.value}
    />
  );
}

export default InputField;



Enter fullscreen mode Exit fullscreen mode

src/components/CheckBox.jsx




function CheckBox(props) {
  return (
    <input
      type="checkbox"
      checked={props.checked}
      onChange={props.onChange}
      class="w-4 h-4 md:w-6 md:h-6 flex-shrink-0"
    />
  );
}

export default CheckBox;



Enter fullscreen mode Exit fullscreen mode

src/components/Navbar.jsx




function Navbar() {
  return (
    <nav className="flex items-center justify-between px-2 py-4 bg-gray-100">
      <div>
        <h6 class="text-2xl font-bold">SolidJs Todo App</h6>
      </div>
      <ul>
          <li>
            <a
              href="https://github.com/harshmangalam/solidjs-tailwindcss-todo"
              class="flex items-center space-x-2 bg-black text-white rounded-full p-1 md:px-4 md:py-2"
            >
              <svg fill="currentColor" class="h-6 w-6 text-white ">
                <path
                  fill-rule="evenodd"
                  clip-rule="evenodd"
                  d="M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.606 9.606 0 0112 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48C19.137 20.107 22 16.373 22 11.969 22 6.463 17.522 2 12 2z"
                ></path>
              </svg>
              <span class="hidden md:block">Github</span>
            </a>
          </li>
        </ul>
    </nav>
  );
}

export default Navbar;



Enter fullscreen mode Exit fullscreen mode

src/App.jsx





import { createEffect, createSignal, For } from "solid-js";
import { createStore } from "solid-js/store";
import Navbar from "./components/Navbar";
import InputField from "./components/InputField";
import Button from "./components/Button";
import CheckBox from "./components/CheckBox";

function App() {
  const [store, setStore] = createStore({
    todos: [],
  });

  const [text, setText] = createSignal("");

  createEffect(() =>
    console.log(
      store.todos.map((s) => ({ text: s.text, completed: s.completed }))
    )
  );

  return (
    <div class="min-h-screen flex flex-col justify-between space-y-4">
      <header>
        <Navbar />
      </header>
      <main class="container md:max-w-lg mx-auto flex-grow">
        <section class=" flex items-center space-x-2 bg-purple-100 px-2 md:px-4 py-6">
          <InputField
            value={text()}
            onInput={(e) => setText(e.currentTarget.value)}
          />
          <Button
            bg="purple"
            class="flex items-center space-x-1"
            onClick={() => {
              setStore({
                todos: [
                  ...store.todos,
                  {
                    text: text(),
                    completed: false,
                  },
                ],
              });
              setText("");
            }}
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              class="h-5 w-5"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                stroke-width="2"
                d="M12 6v6m0 0v6m0-6h6m-6 0H6"
              />
            </svg>
            <span>Add</span>
          </Button>
        </section>

        <section class="py-4 grid grid-cols-1 gap-2">
          <For each={store.todos}>
            {(todo, i) => {
              const { completed, text } = todo;

              return (
                <div class="flex items-center space-x-2 bg-green-100 px-2 md:px-4 py-4">
                  <CheckBox
                    checked={completed}
                    onChange={(e) =>
                      setStore("todos", i(), { completed: e.target.checked })
                    }
                  />
                  <InputField
                    value={text}
                    onInput={(e) =>
                      setStore("todos", i(), { text: e.currentTarget.value })
                    }
                  />
                  <Button
                    bg="red"
                    class="flex items-center space-x-1"
                    onClick={() =>
                      setStore("todos", (t) => [
                        ...t.slice(0, i()),
                        ...t.slice(i() + 1),
                      ])
                    }
                  >
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      class="h-6 w-6 text-white"
                      fill="none"
                      viewBox="0 0 24 24"
                      stroke="currentColor"
                    >
                      <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
                      />
                    </svg>
                  </Button>
                </div>
              );
            }}
          </For>
        </section>
      </main>
      <footer class="py-2 bg-gray-100">
        <p class="text-center">SolidJs Todo - {new Date().getFullYear()}</p>
      </footer>
    </div>
  );
}

export default App;



Enter fullscreen mode Exit fullscreen mode

github repo here

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs