Mesh gradients look awesome. There's just something subtle and calming about the way the colors and shadows blend together to create an illuminating background.
I really like the creative flair they add to websites - in fact I'm using one right now on my homepage for shaunchander.me
Today, we're building our own animated mesh gradient with whatamesh.
đ Get started
Let's bootstrap a new React project with create-vite-app
.
npm create vite@latest
Vite will ask you a series of questions. I'm using React + Typescript w/SWC for this tutorial.
Installing TailwindCSS
Now let's get TailwindCSS installed. This step isn't required though if you do not want to use TailwindCSS in your project.
npm i -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Don't forget to configure your tailwind.config.cjs
file!
// tailwind.config.cjs
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Now let's add a tailwind.css
. First create a styles
directory, then add tailwind.css
to it.
// tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;
Then add this tailwind.css
file as an import inside of main.tsx
.
// main.tsx
import "./styles/tailwind.css";
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
// ...
Cleaning out the clutter
Let's get rid of a few files Vite ships by default. Go ahead and remove App.css
index.css
, and that random React logo in assets
(make sure you update imports inside of main.tsx
).
Then clear our your App.tsx
and replace it with the following.
// App.tsx
export default = () => {
return <div>Woah, look at this whatamesh gradient.</div>;
};
Let's verify everything is working as expected by running npm run dev
and visiting our dev server. You should see something like this:
Alright, let's move onto getting whatamesh configured.
đ¨âđģ Configuring whatamesh
whatamesh is not an npm package, rather, it's a good ol' JavaScript... script.
That said, the way you're supposed to use whatamesh is by importing it from a JavaScript file. Inside of the src/assets
directory, let's create a new file called gradient.js
.
Then, paste the contents of the whatamesh gradient script into that file!
Now back inside of our App.tsx
file, let's import the gradient by doing the following:
import { Gradient } from "./assets/gradient"
You'll notice that ./assets/gradient
gets flagged by TypeScript because it doesn't have any type definitions. This is unfortunately a downside with whatamesh - it's written entirely in JS only. Lucky for us, we can quickly get around this by making our own type declaration file.
Let's add a gradient.d.ts
file inside of our assets
directory.
// gradient.d.ts
export declare class Gradient {
initGradient(id: string): void;
}
For those unfamiliar with *.d.ts
file, they essentially let us define TypeScript types for JavaScript files. Lucky for us we only need to call this initGradient()
function, which is a member of the Gradient
class. I'll leave you to digest the syntax đ.
./assets/gradient
type error go away.Okay TypeScript shenanigans aside, let's actually get to using whatamesh.
To get started, you'll need to include a <canvas />
element somewhere on the page, this is where whatamesh will render its animated mesh gradient into.
Let's go ahead and add this into our App.tsx
file.
// App.tsx
<main>
<div>
<h1>
Woah, look at this whatamesh gradient.
</h1>
</div>
<canvas
id="gradient-canvas"
data-transition-in
/>
</main>
You'll notice that I enhanced our HTML with a <main />
wrapper tag and a new <h1 />
tag. Let's follow good HTML semantics while we're at it đ.
Now what we need to do is add some styling into our tailwind.css
file. Go ahead and throw in the following:
@layer components {
#gradient-canvas {
width: 100%;
height: 100%;
--gradient-color-1: #c3e4ff;
--gradient-color-2: #6ec3f4;
--gradient-color-3: #eae2ff;
--gradient-color-4: #b9beff;
}
}
You'll notice that this selector actually defines the gradient colors! whatamesh only has 4 color stops that you can configure. I personally recommend having 1 unique color stop and have the remaining 3 be the same color. Too many colors can lead to a pretty chaotic (and annoying) background đ .
If you want to use my colors from my homepage:
--gradient-color-1: #07f49e;
--gradient-color-2: #1d1241;
--gradient-color-3: #1d1241;
--gradient-color-4: #1d1241;
Now that we have the <canvas />
element in place, all that's left to do is to initialize the gradient. We can do this using a useEffect
hook.
// App.tsx
import { useEffect } from "react";
import { Gradient } from "./assets/gradient";
export default () => {
useEffect(() => {
const gradient = new Gradient();
gradient.initGradient("#gradient-canvas");
}, []);
return (
<main>
<div>
<h1>
Woah, look at this whatamesh gradient.
</h1>
</div>
<canvas
id="gradient-canvas"
data-transition-in
/>
</main>
)
}
đ¤ Wait! Before you check your dev server, let's actually add some quick styling to our App.tsx
component!
<main className="min-h-screen flex flex-col relative bg-slate-900">
<div className="relative z-10 flex flex-col flex-1 justify-center max-w-6xl p-10">
<h1 className="text-7xl font-bold text-white">
Woah, look at this whatamesh gradient.
</h1>
</div>
<canvas
id="gradient-canvas"
className="fixed inset-0"
data-transition-in
/>
</main>
What we've essentially done is:
- make
<main />
take up the full page height and have it be a relative container - give some styling to the
<h1 />
text - make our
<canvas />
element span the full width and height of the our<main />
container so the gradient looks full screen.
Okay now let's check the dev server:
đđ Perfect.
And... that's it! You're now up and running with whatamesh đ.
Here's a link to the final GitHub repository as well as a demo of what we built in action.