In this morning quick start, we are going to bootstrap a create-react-app
with Tailwind and see how you can get it all up and running quickly with some state-based styling using classnames
.
Installation
First, we need to create the TypeScript React app with create-react-app
.
Second, we will install the other packages required for today.
# Create the app
npx create-react-app hello-tailwind --template typescript
# Change into our new app
cd hello-tailwind
# Using Yarn
yarn add tailwindcss classnames @types/classnames
Updating package.json
This part took quick inspiration from Dave Ceddia's post with a modern update.
Let's update our scripts to have the following:
{
"scripts": {
"build:tailwind": "tailwindcss build src/index.css -o src/tailwind.output.css",
"prestart": "npm run build:tailwind",
"prebuild": "npm run build:tailwind"
}
}
prestart
and prebuild
scripts will run before any start
and build
script that is run. We are telling it to build the index.css
file and output it to src/tailwind.output.css
.
Add Tailwind imports
Update src/index.css
to look like the following:
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
Then, we will need to update our index.tsx
file to change the import from index.css
to tailwind.output.css
:
import React from "react"
import ReactDOM from "react-dom"
import "./tailwind.output.css"
import App from "./App"
import * as serviceWorker from "./serviceWorker"
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
)
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister()
Now we are ready to run!
Playing around with App.tsx
Run yarn start
to get our application up and running.
Once up, let's update our App.tsx
file to look like the following:
import React from "react"
function App() {
return (
<div className="bg-gray-200 flex items-center justify-center h-screen">
<button
className="p-3 rounded-sm bg-blue-500 hover:bg-blue-700"
onClick={() => setToggle(!toggle)}
>
Toggle
</button>
</div>
)
}
export default App
When we run the app, we should now get the following:
These classnames come from the Tailwind docs. The docs are very user friendly! Search for your CSS properties and apply them from there.
As an added bonus, if you are a VSCode user, check out their VSCode extension to help autocomplete classnames!
Updating the App.tsx file to work based on logic
We can now add logic based on useState
to toggle between different states.
Update App.tsx
to show the following:
import React from "react"
// import cx from 'classnames';
function App() {
const [toggle, setToggle] = React.useState<boolean>(false)
console.log("toggle", toggle)
const buttonClasses = toggle
? "bg-red-500 hover:bg-red-500"
: "bg-blue-500 hover:bg-blue-500"
return (
<div className="bg-gray-200 flex items-center justify-center h-screen">
<button
className={`p-3 rounded-sm ${buttonClasses}`}
onClick={() => setToggle(!toggle)}
>
Toggle
</button>
</div>
)
}
export default App
Once we run the app now, if we click the button we will see the background change to red!
Using classnames
For more complex logic, we can use the classnames package to help us define which classnames to apply.
import React from "react"
import cx from "classnames"
function App() {
const [toggle, setToggle] = React.useState<boolean>(false)
const buttonClasses = cx({
"bg-blue-500 hover:bg-blue-700": !toggle,
"bg-red-500 hover:bg-red-500": toggle,
})
return (
<div className="bg-gray-200 flex items-center justify-center h-screen">
<button
className={`p-3 rounded-sm ${buttonClasses}`}
onClick={() => setToggle(!toggle)}
>
Toggle
</button>
</div>
)
}
export default App
While this example is trivial, it becomes important for when you are defining variants based on props. We could swap out toggle
to be logic such as status === 'error'
, etc. to reflect different possibilities through our application.
Conclusion
This has been a quick morning coffee and blog post on getting up and running with Tailwind without getting into the nitty-gritty details.
Tailwind has a great reputation and for good reason - I highly recommend using this playground to try out what else it does offer.
Resources and Further Reading
- VSCode extension
- Tailwind - Installation
- Tailwind - Flex
- Tailwind - Text Color
- Tailwind - Background Color
- Tailwind - Border Radius
- Tailwind - Padding
- Tailwind with CRA - Dave Ceddia
- Classnames - GitHub
Image credit: Mael BALLAND
Originally posted on my blog. Follow me on Twitter for more hidden gems @dennisokeeffe92.
Top comments (3)
do you recommend converting your codebase from javascript to typescript ? Lately there are a lot of engineers doubling down on Typescript. My shop store app is already like medium to large sized.
Depends really. If I have larger projects, I will use TypeScript as your "first point of testing" then becomes static typing. It will stop you from making some easy mistakes that can happen. If I am doing a short project or just writing short scripts, I don't bother. It becomes too much overhead.
The reason I actually decided to start getting into Tailwind is that I was using Styled Components with Styled System inside my design system and the cost maintain the types for those libraries became a nightmare that just wasn't worth it. I am still using TypeScript for the design system, but I am no longer bothering to type the styles. It just impeded on my ability to create way too much :(
thanks a lot man ! appreciate it