Solid is a lightweight JavaScript library used to build fast, performant websites. Its small bundle size and highly effective reactivity model have made it popular amongst developers — Solid even won the title of Breakthrough of the Year at the 2022 Open Source Awards.
In this guide, we will explore what makes Solid a fantastic choice for building applications that require speed and high performance.
Solid was created by Ryan Carniato in 2018. He used many of the same principles that were used to create React, including a declarative syntax, component-based architecture for modularity, and unidirectional data flow, where data only flows from parent components to children components.
React was instrumental in moving the frontend community along with features like those mentioned above, its virtual DOM, and later on, Hooks. Solid builds on React, adopting and fine-tuning its strengths as well as eliminating weaknesses.
One common issue in React is frequent and excessive updates to the DOM. To tackle this issue, Solid uses a fine-grained reactivity model, which minimizes DOM computations and re-renderings through Signals and effects.
Introducing Signals and effects allowed Solid to take a huge step forward in the frontend ecosystem. Signals allow you to write very reactive code — when a Signal changes, it automatically triggers any code that depends on it.
This was game-changing, as it did away with the idea of re-rendering the entire DOM tree when any changes were made. Signals track any changes and only re-render the components that depend on that change!
Since its creation, the Solid library has seen some significant updates — for example, the addition of enhanced TypeScript compatibility, HTML streaming, server-side error boundaries, and internationalization.
There are many reasons why you should consider choosing Solid for your next project. One of those reasons is its top-tier performance and speed.
Solid is very performant and fast. It has a tiny bundle size and uses Signals and effects in its fine-grained reactive approach. Its use of Signals alone makes Solid a good choice for frontend projects, as we discussed above.
Solid also has support for TypeScript and internationalization. Internationalization means that Solid apps can be adapted to various languages and regions without many changes to the code, while better TypeScript support means that developers can write more type-safe code in their applications.
Lastly, developers using Solid can expect frequent updates and bug fixes. This means that we get to see many more exciting — and hopefully, game-changing — features!
Using Solid comes with many benefits that may convince you to choose it, some of which we’ve already discussed. Despite its many pros, like any library, it also has some cons. We will cover all of these in this section.
Some pros of Solid include:
Some cons of Solid include:
Despite these potential drawbacks, I think there’s still a great case for adopting Solid because of its speed and reactivity. In addition, the more Solid is used, the more the community grows, and the more third-party packages are created for it.
Solid offers many great features that make it a great choice for frontend development. Let’s take a look at some key features you should know.
When building with Solid, it might interest you to know that Solid supports templating through JSX and tagged template literals.
JSX is widely known and used due to its straightforward syntax, tooling support, and component structure, which can help simplify the development setup and process as well as make your app more scalable and maintainable. It also works well with Babel, making your JSX executable in the browser.
Tagged template literals provide a way to process template literals with a function. This allows you to transform the string values of template literals dynamically and create custom, complex logic as needed while keeping your code clear and maintainable.
Components are the building blocks of a Solid application. They are responsible for rendering the UI of your app.
In Solid, components are created as functions. Solid components are reactive and only re-render when the date they depend on changes. An example of this is shown below:
function App() { const [data, setData] = useState([]); return <( {data().length > 0 && <ShowHeaser/>} ) }
In the above example, we created a signal that holds an array, and we want to show a component when the array length is greater than zero. In Solid, only the component that depends on the array will re-render when the array length changes.
Components in Solid encourage composition. This is when components are nested together to create other components.
Let’s see an example of component composition. Say we create a reusable button
component:
function Button(props) { return <button>{props.label}</button>; }
We can use that button
component in a card
component and also nest the button
component there:
function Card(props) { return ( <div class="card"> <h2>{props.title}</h2> <p>{props.content}</p> <div> <Button label="Click me" /> </div> </div> ); }
The above example demonstrates how composition allows you to break down your application into small chunks that can be easily built and debugged.
Props are the de facto way of transferring data between components. Props are read-only, which means that children components can use props but can’t directly change them. Here’s an example:
import ChildComponent from './ChildComponent'; function ParentComponent() { const name = 'Alice'; return ( <div> <ChildComponent name={name} /> </div> ); }
Solid props allow you to create flexible and reusable components by configuring them as needed. They are a fundamental part of Solid applications.
Signals are an essential part of the fine-grained reactivity model in Solid. When a Signal is used, it ensures that only the things that need to change are changed.
Signals work using the observer pattern. This pattern ensures that a one-to-many relationship is created in a list of objects and that, when one object changes, only the other objects that depend on that change are notified.
The Signals feature in Solid is one of many factors contributing to this library’s outstanding performance. This feature virtually eliminates the need for expensive DOM calculations and re-rendering.
Effects are functions that run whenever a specific tracked signal changes. Almost identical to the useEffect
Hook in React, an effect does a certain thing when a tracked signal changes. An example of this can be side effects like data fetching in your application.
The difference between effects in Solid and the useEffect
Hook in React is that we must manually pass a dependency array to the useEffect
Hook to see if it changes. Meanwhile, this is automatically handled in Solid, which makes it more predictable as there is no need to manually pass a dependency array.
Effects also have an automatic cleanup function that makes sure there are no memory leaks caused by unhandled side effects.
When writing conditionals in React, we use the ?
and :
ternary operators. While this syntax is also available in Solid, you can also handle conditionals in Solid with the <Show>
component.
For example, in React, we would have the code below to conditionally show a message when the number is 2
and another when the number isn’t 2
:
const Counter = () => { const [number, setNumber] = useState("0"); return ( <h2>The number is: {number}</h2> <div style={{ display: "flex" }}> <button onClick={() => setNumber(number + 1)}>Increase</button> <button onClick={() => setNumber((prev) => prev - 1)}>Decrease</button> </div> {number === 2 ? "The number is two": "The number isn't two"} ); };
In Solid, the same example should be written as follows:
const Counter = () => { const [number, setNumber] = createSignal("0"); return ( <h2>The number is: {number()}</h2> <div style={{ display: "flex" }}> <button onClick={() => setNumber(number() + 1)}>Increase</button> <button onClick={() => setNumber((prev) => prev - 1)}>Decrease</button> </div> <Show when={number() === 2} fallback={"The number isn't two"}> The number is two </Show> ); };
The approach in Solid offers better reactivity, simpler re-rendering, and more predictable updates.
React provides the Array.prototype,map()
method for looping through a list of items and displaying them. While you can still use the Array.prototype,map()
in Solid, you can also use the provided <For>
helper method to loop through an array of items as shown below:
const EpisodeBox = ({ episode }) => { return ( <For each={episode.characters.slice(0, loadCount())} fallback={<p>Loading...</p>} > {(character) => <CharacterDetails characterUrl={character} />} </For> ); }; export default EpisodeBox;
This approach is more explicit and automatically generates keys, thereby cutting out the need to generate unique keys for arrays through third-party packages and dependencies.
Solid provides us with the onMount
and onCleanup
lifecycle methods, which we can use to handle various tasks in a component at different points of the component’s lifecycle.
onMount
is a lifecycle method that runs when a component renders for the first time. This lifecycle method runs just once and never reruns. You can use onMount
to call any endpoint or fetch any resource that your app might need when it loads.
onCleanup
is the opposite of the onMount
method — it runs whenever a component is removed from the DOM. You can use this lifecycle method to clear any effects or listeners.
Batching in Solid allows you to sequence multiple state updates into a single operation. This is extremely useful when you have state changes that rely on one another. Here is an example below:
function MyComponent() { const [count, setCount] = createSignal(0); const increment = () => { batch(() => { setCount(count() + 1); setCount(count() + 1); }) }; return ( <div> <p>Count: {count()}</p> <button onClick={increment}>Increment</button> </div> ); }
The batching feature helps reduce unnecessary re-renders and ensures efficient updates in Solid projects.
Solid is ideal for building applications that deal with large amounts of data, high volumes of traffic, real-time updates, and more. Even in simpler applications, Solid can help with creating a more fluid user experience, improving SEO, and reducing latency.
Some example practical use cases for Solid could include, but are certainly not limited to:
You can effectively build and manage many different types of applications with Solid due to its high performance and speed. This makes Solid a great choice for businesses of almost any size, from startups to enterprises.
Solid also supports testing with Jest and Vitest. In addition, you can benefit from Solid Developer Tools, a library that provides developer tools, a reactivity debugger, and a Devtools Chrome extension that allows you to visualize and interact with the reactivity graph in Solid.
Styling in Solid is a breeze, especially for developers coming from a React background. Solid natively supports styling with inline styles, classes, and CSS modules.
The only difference between styling in Solid and React is that while inline styling in React uses camelCase
, styling in Solid uses the dash -
method. Let’s see an example below:
function App() { const fontWeight = "bold"; return ( <> <h1 style={`color: red; font-weight: ${fontWeight};`}> Hello World </h1> </> ); }
As seen in the example above, we wrote the inline styling for font-weight
with a dash instead of camelCase
as in the case of React.
Solid also supports third-party packages for styling and animating apps, like Tailwind CSS, SASS, UnoCSS, Motion One, and more. Third-party packages are the safest bet when building large-scale Solid applications that will need dynamic styling, reusable components like forms or buttons, and theming.
Throughout this guide, we’ve been mentioning some similarities and differences between Solid and React. In this section, we’ll briefly compare them in terms of performance, state management, community, tooling, out-of-the-box features, and more:
createSignal
or createStore
in the global scope of your applicationHere’s a table that summarizes our comparison of Solid vs. React:
SolidJS | React | |
---|---|---|
Performance | Highly performant | Not as performant as SolidJS |
Unidirectional data flow | ✅ | ✅ |
Virtual DOM | No, manipulates the DOM directly | Uses a virtual DOM |
Excessive re-rendering | Re-renders only what changes | Re-renders everything with any change |
Community and ecosystem | Growing community | Very rich community and ecosystem |
Bundle size | A very small bundle size (22.8kB minified) | Larger (100 KB minified) |
Hydration (server-side rendering) | ✅ | ✅ |
Suspense | ✅ | ✅ |
Internationalization | ✅ | ✅ |
TypeScript support | ✅ | ✅ |
As you can see, Solid is a great choice for frontend projects of almost any kind or size. While its community is younger and smaller than React’s, Solid essentially shares all the benefits React offers while providing greater speed and performance.
SolidJS is a great framework and one that I think has the potential to become the next best thing in the frontend ecosystem. But you don’t have to just take my word for it — you can see by its steadily growing list of contributors and community members that SolidJS is an increasingly popular library, and for good reason.
The use of Signals in particular will be instrumental in the frontend landscape. I expect that we’ll see new frameworks adopt this approach and become faster and more performant.
Even once other frameworks adopt Signals, SolidJS has many other benefits that make it worth your time — like its bundle size, consistent and glitch-free state updates, use of effects to track Signals automatically, and cleanup function to protect against memory leaks that might be caused by side effects.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowReact Native’s New Architecture offers significant performance advantages. In this article, you’ll explore synchronous and asynchronous rendering in React Native through practical use cases.
Build scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.