Random Color Generator

background: #000000;

Introduction

Fooderia, the vibrant and engaging food recipe site you are currently working for, seeks to enhance the user experience by incorporating visually appealing and dynamic elements into its design. One innovative feature they decided to implement is a Theme of the Day that changes the visual motif of the website daily to keep the interface fresh and inviting. There are big plans for this feature, but for now, the team has asked you to create a simple random color generator that will generate a random color when the user clicks a button, to be showcased in the next demo session later this week.

Tutorial

Eh, OK, no questions asked, right? Let's get to work! You can't really tell how this random color thingy is going to be used yet, but you decide to encapsulate this in one single component. You don't even know what kind of format they prefer for their random colors, so you choose to make it configurable for two formats that can be used in CSS, a hex variant #rrggbb and an RGB variant rgb(r, g, b).

You start by creating a skeleton of the component:

components/RandomColorGenerator/RandomColorGenerator.jsx
import { useState } from 'react'

export function generateRndColor () {
// TODO: Implement this function
return [0, 0, 0]
}

// The component takes an isHex property that will control the
// format of the css to be used
export default function RandomColorGenerator ({ isHex = true }) {
// you create a state for the current color used represented
// by an array of 3 numbers i.e. [r, g, b]
const [color, setColor] = useState ([0, 0, 0])

// Style the component using Tailwind CSS to the best of your ability
return (
<div className="p-4 flex gap-4 border">
<p className="self-center">
<button className="text-blue-400 hover:text-blue-300 active:opacity-80">[Generate]</button>
</p>
<div className="flex flex-1 min-h-24 p-2 justify-start rounded-lg items-center">
<p className="bg-black rounded-md p-2 opacity-80 font-mono">{color}</p>
</div>
</div>
)
}

And an index file for the component; note it has to be a client-side component since you are using the useState hook in it:

components/RandomColorGenerator/index.js
'use client' // <- Notice this line
export { default } from './RandomColorGenerator'

And finally, you create a page to showcase the component:

app/random-color/page.jsx
import RandomColorGenerator from '@/components/RandomColorGenerator'

export default function RandomColorPage () {
return (
<main className="flex flex-col gap-8 p-4 sm:p-24">
<h1 className="text-xl font-bold">Accordion</h1>
<h2>rgb()</h2>
<RandomColorGenerator />
<h2>#hex</h2>
<RandomColorGenerator isHex />
</main>
)
}

Great stuff! Now it's time to make the button actually generate a random color and make sure we can get a decent CSS string out of it.

components/RandomColorGenerator/RandomColorGenerator.jsx
import { useState } from 'react'

function generateRndColor () {
// Using the javascript Math.random () function that generates
// a random decimal number between 0 and 1, multiply it by 256
// and round it down to create a random number between 0 and 255
// This will generate an array of 3 random numbers between 0 and 255.
return [0, 0, 0].map (() => Math.floor (Math.random () * 256))
}

// To be able to set a color with css you need to convert the color array
// to a css color string:
function getCssColor (color, isHex = false) {
// If the isHex is true, convert the color array to a hex string
// by mapping through the array and converting each number to a
// 2 digit hex string using the toString (16) method and padding
// it with a '0' if it's less than 2 digits. Then join the array
// to create a hex string and prepend it with a '#'
return (
isHex ? '#' + color.map (value => value.toString(16).padStart (2, '0')).join ('')
// If isHex is false, convert the color array to an rgb string
// by joining the array with a comma and a space
: `rgb(${color.join (', ')})`)
}

export default function RandomColorGenerator ({ isHex }) {
const [color, setColor] = useState ([0, 0, 0])

return (
<div className="p-4 flex gap-4 border">
<p className="self-center">
{/* Add a click handler that generates and set a new random color */}
<button onClick={() => setColor (generateRndColor ())} className="text-blue-400 hover:text-blue-300 active:opacity-80">[Generate]</button>
</p>
<div className="flex flex-1 min-h-24 p-2 justify-start rounded-lg items-center">
{/* Display the color as a css color string */}
<p className="bg-black rounded-md p-2 opacity-80 font-mono">background: {getCssColor (color, isHex)};</p>
</div>
</div>
)
}

It generates a usable string! In your excitement over the wonders you are capable of, you almost forget to style some element with the generated string. You recognize that generating a background color class for Tailwind CSS is more complicated than one might think, but also that you just might use the inline style attribute of the element here; it does suffice in this case.

components/RandomColorGenerator/RandomColorGenerator.jsx
//...

export default function RandomColorGenerator ({ isHex }) {
const [color, setColor] = useState ([0, 0, 0])

return (
<div className="p-4 flex gap-4 border">
<p className="self-center">
<button onClick={() => setColor (generateRndColor ())} className="text-blue-400 hover:text-blue-300 active:opacity-80">[Generate]</button>
</p>
{/* ↓ The magic ↓ */}
<div style={{ background: getCssColor (color, isHex) }} className="flex flex-1 min-h-24 p-2 justify-start rounded-lg items-center">
<p className="bg-black rounded-md p-2 opacity-80 font-mono">background: {getCssColor (color, isHex)};</p>
</div>
</div>
)
}

And there you have it! A random color generator that can generate colors in both hex and RGB formats. The Fooderia team was not just satisfied with the outcome; they were inspired by it. The success of the random color generator has set a new benchmark for how they approach website features in the future, emphasizing user engagement, design innovation, and the impactful use of technology to create a lively and engaging platform. You wonder what they have in store for you next?