CSS

Introducing the New SolidJS and Tailwind CSS Starter Kit

Mark Shenouda
4 min read
Introducing the New SolidJS and Tailwind CSS Starter Kit
This article was written over 18 months ago and may contain information that is out of date. Some content may still be relevant, but please refer to official documentation for the latest information.

We are delighted to announce our SolidJS + Tailwind Starter Kit on Starter.dev to help you build your next project with SolidJS and Tailwind CSS in no time. In this article, we will walk you through the kit, and how it is a great option for building your next project. This kit has been designed to build tiny and optimized web applications on both the JavaScript and CSS sides. It's very useful when the load time of your application's files is critical, like when the internet connection is slow or when you are building a mobile application for a targeted audience.

Why SolidJS?

SolidJS is a declarative, efficient, and flexible JavaScript library for building user interfaces. It lets you build web applications using a declarative API that you’re already familiar with. It’s a great alternative to React, Vue, and other popular JavaScript frameworks. It’s also a great choice for building static sites. The best feature of SolidJS is how tiny its build bundles are. It helps you ship less JavaScript to the browser.

Why Tailwind CSS?

Tailwind CSS is a utility-first CSS framework for rapidly building custom user interfaces. It makes it easy to build complex UIs without having to write custom CSS. And the best feature of Tailwind CSS is how customizable it is. It helps you ship a very small CSS file to the browser.


Starter Kit Features

  • SolidJS - A declarative, efficient, and flexible JavaScript library for building user interfaces.
  • Tailwind CSS - A utility-first CSS framework for rapidly building custom user interfaces.
  • Vite - A build tool that aims to provide a faster and leaner development experience for modern web projects.
  • Storybook - An open-source tool for developing UI components in isolation for React, Vue, and Angular.
  • Vitest - A fast and simple test runner for Vite.
  • TypeScript - A typed superset of JavaScript that compiles to plain JavaScript.

Tailwind CSS

Tailwind CSS makes it easy to build complex UIs without having to write custom CSS. The best feature of Tailwind CSS is how customizable it is. It helps you ship a very small CSS file to the browser. Also, Tailwind CSS is great at scale, so you can add as many utilities as you want.

Storybook

Storybook is an open-source tool for developing UI components in isolation for React, Vue, Angular, and others. It makes building stunning UIs organized and efficient. It also helps you build components faster, and reuse them in your projects. It also helps you document your components. This kit comes with Storybook pre-configured. You can start using it right away.

Why Vite?

Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. It's a great alternative to Webpack. It's fast and easy to use. It also helps you ship less JavaScript to the browser. It's a great choice for building static sites. This kit comes with Vite pre-configured. You can start using it right away.

Testing

This kit comes with Vitest pre-configured. Vitest is a tool that is built with Vite in mind from the start, taking advantage of its improvements in DX, like its instant Hot Module Reload (HMR). This is Vitest, a blazing fast unit-test framework powered by Vite. It's a great alternative to Jest. It's fast and easy to use.

How to get started?

  • Run npx @this-dot/create-starter to start a new project from one of the kits in the Starter CLI library.
  • Select the SolidJS, Tailwind kit from the CLI library options
  • Name your project
  • cd into your project directory and install dependencies using the tool of your choice (npm, yarn or pnpm)
  • Copy the contents of the .env.example file into a .env file

When to use this kit?

This kit is a great alternative to React and SCSS. It focuses on performance and developer experience by providing a fast and leaner development experience for modern web projects. It also helps you write less CSS, and less JavaScript.

Options to scale the kit to fit your needs

In this section, we will walk you through the options you have to scale the kit even further to fit your needs. We didn't want to add too many options to the kit in order to keep it simple and easy to use, but we also wanted to provide you with the ability to scale the kit.

PWA

PWA is a great way to make your app available offline, and installable on mobile devices. It caches your app's assets to make it load faster. It also helps you build a great user experience, and increase your app's engagement by providing push notifications. If you want to add PWA support to the kit, you can use the PWA Vite Plugin to add PWA support to the kit. It covers the PWA integrations for Vite, and the ecosystem with zero-configuration and is framework-agnostic.

Conclusion

So as we discussed in this article this SolidJS starter kit is a great way to start your new SolidJS project because it has most of the tools you need installed and preconfigured for you from Storybook to Testing, and even the PWA configurations. We hope you enjoyed this article, and we hope you will enjoy using the kit. If you have any questions or suggestions, please feel free to reach out to us on Twitter or Contact form.

About the author

Mark Shenouda

Mark Shenouda

Software Engineer

Keep reading

View all posts →

Understanding Effects In SolidJS

In SolidJS, effects are a fundamental concept that helps developers manage side effects and reactive dependencies within their applications. ...

Victor Umeh3 mins
SolidJS

The CSS / Utility hybrid approach with Tailwind v4

The post concludes with a look at modern CSS and interesting hybrid utility patterns with the Tailwind v4 release...

Dane Grant4 mins
Tailwind CSSCSS

Deep Dive Into How Signals Work In SolidJS

SolidJS and Qwik have shown the world the power of signals, and Angular is following suit. There’s no way around them, so let's see what they are, why one would use them, and how they work. Signal basics Signals are built using the observer pattern. In this pattern, a subject holds a list of observers who are subscribed to changes to the subject. Whenever the subject gets changed, all subscribers will receive a notification of the update. Typically through a registered callback method. Observers may push new changes to that subject or other subjects. Triggering another set of updates throughout the observers. From the above, you might have guessed that infinite loops are a big caveat with using the observer pattern. The same holds true for signals. The power of this pattern lies in the separation of concerns. Observers need to know little about the subject, except that it can change. Whichever actor is going to change the subject needs to know nothing about the observers. This makes it easy to build standalone services that know only about their domain. Signals in front end frameworks SolidJS brings the observer pattern to the table for front end frameworks through signals. Observers can be added to a signal through SolidJS’s concept of Effects (by using createEffect). Components within SolidJS can be seen as both an observer and a subject at the same time. The component subscribes to all signals that are used to render the components HTML. SolidJS’s rendering system, in turn, is subscribed to all components. Where the components act as subjects and SolidJS as an observer. So whenever a signal changes in a component, the component reacts by changing its output, which then triggers SolidJS to put the new output on the screen. Compare this to, for example, Vue or React. When a change to the state occurs, the new values are passed down the component hierarchy. Each component returns its new output, which can be either the same as the previous render or changed. The framework then compares this tree against what it already had, and determines which parts to update. This is more dependent on a single source of truth which needs to know about all the components in the system. Changes are loosely related to each other, and only by diffing the results can the next step be determined. This differs from SolidJS setup, which makes hard connections between changes and results, making what will get updated when a signal changes more straightforward. Writing our own Signals At first sight, signals seem magical, and one might be inclined to believe there are some compiler tricks going on. Yet it is all plain JavaScript, and in this article, we’ll demystify signals in order to use them to their full potential. We can create our own signals with pure JavaScript in less than 25 lines. Our simple version will not take objects or arrays as values as these are references in JavaScript and require special attention. Let's start with the interface. We want the signal creator, which is a function that returns a tuple with the first value being the getter and the second value the setter. The function accepts a value, which will be used as the initial value. This gives us: Note that, due to the fact that we created a new variable within the closure of our createSignal, the variable outside of its scope will not change. original on the last line will still be “1”. For simplicity, we’re going to leave objects and arrays out of the picture as these are references instead of scalar values, and need extra code to do the same thing. Now that we can read from and write to our signal (a.k.a. subject), we’ll need to add subscribers to it. Whenever the getter is called (i.e., the value is read), we want the originator of the call to be registered as an observer. Then, when the setter is called, we are going to loop over all subscribed observers, and notify them of the new value. Consider this fully working signal creator. We’re almost there. This snippet has a downside. It needs the observer to be passed as the argument to the getter. But we don’t want to deal with that. Our interface was to read signal(), and have some sort of magic register the observer for us. What comes next was an eye opener for me. I always believed there was some closure trick, or built in JavaScript function to retrieve parent closures. That would have been a fantastic way to get who called the getter function and register it as an observer. But JavaScript offers nothing to support us in this. Instead, a way more simple trick is used, and it is seemingly used in every major framework. Frameworks, among others, React and SolidJS, store the parent in a global variable. Because JavaScript is single threaded, it needs to execute all operations in order. It does a lot under the hood to get stuff like async to work. Clever developers have relied on this single threaded aspect by writing to a global variable, and reading from it in the next function. This gets a little abstract, so here’s a concrete example to demonstrate this setup. We do not need to worry about current getting overwritten, as the code will always execute in order. It’s safe to assume that it will have the value we expect it to have when the body of second is executed. Note that we clear the value in the body of first as we don’t want unwanted side effects by leaving the variable set. The Fully Working Signal Let’s add effects to our signals to complete the minimal signal minimal framework. With what we have learned in the previous section, we can create effects by Registering the effect callback (i.e., the observer) to our global variable current Calling the observer for the first time. This will read all signals it depends upon, therefore adding current to the observer list. Clearing current to prevent registering the observer to signals read in the future. For this, we remove the current argument from the getter, as this is now globally readable. And we can add the createEffect function. With this setup, we already have a working signal system. We can register effects and write out signals to trigger them. And there we have it! Working signals in just a couple of lines, no magic, no difficult JavaScript API. All just plain code. You can play around with the fully working example in this StackBlitz project. It has the signal setup as described, plus an example of stores. Run node index.js to see the result. This simple framework is only focused on showcasing signals. For demonstration purposes, it simply logs to the console. Frameworks like SolidJS have advanced effects and logic to get HTML rendering to work. If you’re interested in learning more about rendering, you can read Mark’s blog on how to create your own custom renderer in SolidJS Or put your newly learned skills to use in a new SolidJS project created with Starter.dev’s SolidJS and Tailwind starter!...

Maarten Bicknese5 mins
SolidJS

How to Create Your Own Custom Renderer in SolidJS

Intro In this article, we will explore what custom renderers are, the problem they solve, and how SolidJS has created a custom renderer that is quite unique because of its simplicity and ease of use. We will also learn how to create a custom renderer in SolidJS, and how to use it in our applications. Custom renderers have a long history with all the major frameworks in the market like Renderer2 in Angular, createRenderer in Vue, and React Reconciler in React. They are used to build awesome technologies and mind blowing libraries. SolidJS recently added the ability to create a custom renderer with Solid Universal Renderer. Note: We also have a great article about How to create a custom renderer for React that you can check out! Custom Renderers in SolidJS To better understand how custom renderers in SolidJS work, we have to understand it first in React and Vue (VDOM frameworks). In React, the library itself (React.js) doesn’t know anything about the DOM. It doesn’t understand what a div or h1 means. React converts all of the components into a JavaScript object that represents the UI in the memory (Virtual DOM), and then update the related nodes when the state changes in specific components. That’s it! This is how React and Vue work under the hood. The React Renderer (which is a different package called “react dom”) then works on rendering this Virtual DOM on the screen, and updates it when it receives updates from React.js. The same thing happens in Vue. From here, the custom renderers have come to live. You aren’t limited to using only the official Renderer for the framework, but you can also build your own.. We will learn more about them in the proceeding sections. But for now, you just need to know that there is no virtual DOM in SolidJS. But it modifies directly on the DOM. This is the only difference between the Custom Renderers in SolidJS and React or Vue. Real world Custom Renderers In this section, I’ll show you the most popular custom renderers that are used in many production applications in different frameworks. One of the most popular custom renderers in the industry is React Native (yes, it’s a React custom renderer for Android and iOS platforms). React three fiber is one of the most famous examples of React Reconciler in production. It converts the JSX VDOM to WebGL graphics. React pdf is a React renderer for creating PDF files on the browser and server. TroisJS is a Vue custom renderer for Three.js and WebGL. There are many, many more examples. HTML Nodes Everything you see on the screen in the web browser is a node; the HTML element is a node, the attribute of that HTML element is a node, for example: Also, the text between and opening and closing tags of this HTML element is a node: Let’s code a SolidJS custom renderer The process is going to be similar to React, but SolidJS Universal is even easier than React Reconciler because it has fewer options. Create a new file to write our renderer and import the createRenderer from SolidJS universal: Second, let’s create an empty renderer: Renderer Options Let’s break all of these options down in detail: createElement This option is responsible for handling the creation of a new element node. It takes only one parameter which is the element type and it could be something like h1, p, divetc And here we can play with the JSX elements for fun. For example, we can add our custom elements like: Technically, there is no HTML component called customLikeButton. But here in this option, we can resolve this type as we desire. createTextNode This option is responsible for handling creating a new text node. It takes only one parameter which is the text itself. replaceText This option is responsible for handling updating the text node when it gets updates. It takes two parameters; the actual text node that has been updated, and the new text. insertNode This option is responsible for inserting or injecting a new node in the UI and the DOM. It takes three parameters, the parent node, the node itself, and a reference node (anchor) in the parent node. removeNode This option is responsible for removing a node from the DOM. It takes two parameters, the parent node, and the node which needs to be removed setProperty This one is a little bit more complicated than the previous ones because it handles more categories. It is responsible for handling the attributes or properties of the element such as the classNames, style, and events like onClick and onSubmit. isTextNode This option is used internally to determine if this node is a text node or not. Note: the node.type in the line above is a pure JavaScript code. In JavaScript nodes have 12 types with 12 numbers each representing a type. For example, 1 represents an element node, and 2 represents an attribute node. For more info see the HTML DOM Element nodeType on W3Schools and Node.nodeType Web APIs MDN. getParentNode This option is being used internally in SolidJS renderer to get the parent node of a given node. getFirstChild This option is being used internally in SolidJS renderer to get the first node of a given parent node. getNextSibling This option is being used internally in SolidJS renderer to get the next node of a given node in the DOM tree. Renderer method There are a lot of methods for this renderer, but the most important one is render which we will replace the SolidJS web one with. There are additional methods available: effect memo createComponent createElement createTextNode insertNode insert spread setProp mergeProps The performance of SolidJS Universal Renderer Ryan Carniato, the creator of SolidJS, created a test on the SolidJS Universal Renderer in his stream of Benchmarking and Custom Renderers on his YouTube channel, and it was pretty interesting. It wasn’t much slower than the SolidJS web renderer at only a few milliseconds slower. To test it, you can use the js framework benchmark repo, which is an amazing tool you can use to compare the performance of different JavaScript frameworks. Conclusion In this article, we learned about the custom renderers in SolidJS and how to create one. We also learned about the performance of SolidJS Universal Renderer and how it compares to the SolidJS web renderer. I hope you enjoyed this article and learned something new. For more SolidJS resources, check out our solidjs.framework.dev where you can find all cool courses, tutorials, and libraries for SolidJS. Also you can create your next SolidJS project, try our SolidJS starter kit from Starter.dev it has a lot of tools pre configured for you. If you have any questions or suggestions, please feel free to send them to us or reach out to us on Twitter....

Mark Shenouda5 mins
Solid RouterSolidJS