- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Guided: Styling a Next.js Finance Application with Daisy UI and Tailwind CSS
In this lab, you will style pieces of an existing Next.js application using Daisy UI and Tailwind CSS. You will become familiar with the advantages of Tailwind CSS and Daisy UI as well as address one of the main concerns of Tailwind CSS, class duplication. By the end of this lab, you should feel confident when styling other applications using these design tools.
Lab Info
Table of Contents
-
Challenge
Introduction
Welcome to the Guided: Daisy UI and Tailwind CSS to Style a Next.JS Finance Application lab.
Throughout this lab, you will become familiar with how to integrate
Tailwind CSSin combination withDaisy UIto an existing finance application.DaisyUIsignificantly reduces the effort required to build modern, responsive web interfaces by providing ready-to-use components while maintaining the flexibility and customization options offered byTailwind CSS.To start, you have been given a
Next.JSapplication without any styling in a few locations. TheNext.JSapplication already performs data fetching and server/client component rendering. You will have the freedom to choose some of the style options from theDaisy UIandTailwind CSS, and by the end of this course, you will have styled a navigation bar, table, and modal. You will also be familiar with how to tackle duplication introduced byTailwind CSSand the basics of how to configureTailwind CSS.You do not need any previous experience with
Next.JS,Daisy UI, orTailwind CSSto complete this lab. This lab assumes you have basic experience withReact,JavaScript,JSXandCSS. Details onNext.JS,Daisy UI, andTailwind CSSwill be given to provide context for your implementations in each step.There is a
solutiondirectory that you can refer to if you are stuck or want to check your implementations at any time. Keep in mind that the solution provided in this directory is not the only solution, so it is acceptable for you to have a different solution so long as the application functions as intended.
Activity
Launch the application by entering
npm run devin the Terminal. The application can be seen in the Web Browser tab atlocalhost:3000. The starting application should look like the picture below:
Remember: throughout the lab, code changes will be live on the website after refreshing if the application is running. If you do however want to stop and restart the application, you can do so by typing
Ctrl+Cin the Terminal and rerunningnpm run dev. -
Challenge
Tailwind CSS Overview
Tailwind CSS Overview
Tailwind CSSis a utility-first CSS framework designed to enable developers to build custom user interfaces quickly and efficiently. Instead of providing pre-styled components like traditional CSS frameworks (e.g., Bootstrap),Tailwind CSSoffers low-level utility classes that can be combined to create any design directly in the HTML. Here are some key aspects ofTailwind CSS:- Utility-First Approach:
Tailwind CSSprovides a large set of utility classes for common CSS properties like padding, margin, color, font size, and more. These classes can be combined to build complex designs without writing custom CSS. For example, the followingdivtag uses utility classes to style it.
<div class="p-4 bg-blue-500 text-white">Hello, Tailwind!</div>- Customization:
Tailwind CSSis highly customizable. Developers can extend the default theme, add custom utility classes, and configure various aspects through the configuration file (tailwind.config.js). In the future, you will configureTailwind CSSto work hand in hand withDaisy UI. In the example below, you can see a custom color being created for an application usingTailwind CSS.
// tailwind.config.js module.exports = { theme: { extend: { colors: { customBlue: '#1E3A8A', }, }, }, }- Responsive Design:
Tailwind CSSincludes built-in support for responsive design with utility classes that can be applied conditionally based on breakpoints. Thedivtag below styles a paragraph to change sizes responsively.
<div class="p-4 sm:p-6 lg:p-8">Responsive Padding</div>- State Variants: It supports state variants like hover, focus, active, and disabled, allowing you to style elements based on their state. The button below would change color when hovered over with a mouse.
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Hover Me</button>- Performance:
Tailwind CSSincludes a tool calledPurgeCSSthat removes unused CSS classes from the production build, significantly reducing the file size. You will not be using purge in this application, but you would add the configuration below if you wanted to use it in the future.
// tailwind.config.js module.exports = { purge: ['./src/**/*.{js,jsx,ts,tsx,html}'], // other configurations... }- Component-Friendly: While
Tailwind CSSitself doesn't provide pre-styled components, it works well with component libraries and frameworks likeReact,Vue, andAngular, making it easy to create reusable components. In this lab, you will also useDaisy UIwhich is built on top ofTailwind CSSto provide pre-styled components, but it is important to note thatTailwind CSScan be quickly used on any component without the use of a design library likeDaisy UI.Tailwind CSScan also be used alongside aDaisy UIcomponent to apply custom styles on the fly.
--- ## Starting with Tailwind CSS
The finance application you are working on already has
Tailwind CSSinstalled as it comes by default with mostNext.jsapplications (unless you select otherwise when creating your application).When you start the application using
npm run devand visitlocalhost:3000in the web browser you will see the following page:
Parts of the application are already using
Tailwind CSSutility classes, but they are being ignored since they cannot be found. In order to locateTailwind CSSutility classes, the global CSS file needs to include a fewTailwind CSSdirectives and have none of your traditional CSS classes or styling. The global CSS must include the following directives.@tailwind base; @tailwind components; @tailwind utilities;These directives import
Tailwind CSSin three layers. The base isTailwind CSS’sPreflightclasses that wipe any browser CSS that may be applied to HTML elements that do not have CSS. The components layer is a small layer that containsTailwind’s component class. Lastly, the utilities layer includes the entirety ofTailwind’s utility classes. With these imports in global CSS, you can useTailwind CSSutility classes in yourHTMLorJSXfiles.Once
Tailwind CSSis imported inapp/globals.css, you can useTailwind CSSthroughout the application in any component, and it is not necessary to have these imports in other CSS files as they will be included globally.
Activity
Currently,
app/globals.cssis an empty file.Import Tailwind CSS by adding the following to the
app/globals.cssfile.@tailwind base; @tailwind components; @tailwind utilities;Refresh
localhost:3000, you should see the app is already different asTailwind CSSutility classes that were already being used to style existing HTML elements can be found. The application should now look like:
- Utility-First Approach:
-
Challenge
Daisy UI Overview
Daisy UI Overview
Daisy UIis a popular component library built on top ofTailwind CSS. It provides a set of pre-designed, responsive, and customizable UI components that are easy to integrate and use in web projects.Daisy UIsimplifies the development process by offering a wide range of styled components, such as buttons, forms, cards, and more, without the need to write extensive custom CSS.Here are some key features of
Daisy UI:-
Tailwind CSSIntegration:Daisy UIworks seamlessly withTailwind CSS, leveraging its utility classes to provide a consistent design system. -
Customizable Components: Components can be easily customized using
Tailwind CSSclasses, allowing developers to tailor them to their specific design needs. -
Responsive Design: Components are designed to be responsive out of the box, ensuring they work well on different screen sizes.
-
Ease of Use:
Daisy UIcomponents are easy to use and can be quickly integrated into projects, reducing the time and effort required to build a polished user interface. -
Theme Support:
Daisy UIincludes built-in theme support, making it simple to apply different color schemes to your project.
--- ## Get Started with Daisy UI
The finance application used throughout this lab already has
Daisy UIinstalled and can be found in thepackage.jsonfile.To use Daisy UI in the application, you must configure
Tailwind CSSto require Daisy UI as a plugin.
Activity
Add the following to the
tailwind.config.jsfile:module.exports = { … plugins: [require('daisyui')], }Now,
Daisy UIis available throughout the application! Parts of the application were already usingDaisy UIclasses to style and transform certain HTML elements into Daisy UI components.Refresh
localhost:3000, and you should now see a home page that looks like:
-
-
Challenge
Styling the Navigation Bar Links
Styling the Navigation Bar Links
When you start up your application, you will see a navigation bar that looks like this:

Navigate to
app/(ui)/components/nav-bar.jsxwhere this navigation is being created. You will be restyling this component to be a beautiful navigation bar using Daisy UI and Tailwind CSS.To style the navigation bar, you will begin by styling the navigation links. Follow the steps below to style the navigation links using Daisy UI and Tailwind CSS.
- Transform your Next.JS
Linkelements to be Daisy UIButtoncomponents by addingclassName="btn"to theLinktag. Thebtnclass is a Daisy UI class that can be applied to any HTML tag to style it like aButtoncomponent.- Example
LinkDaisy UIButton
<Link href="/" className="btn"> Home </Link>- Note: You can refresh the webpage and see that the navigation links should now look like buttons thanks to Daisy UI,
- Example
- Remove the
|and spaces between eachLinkelement. These were here to separate navigation elements before they were styled. - Add a color of your choice to the navigation buttons using Daisy UI button color modifications. Color modifications are added to an elements class name list.
- Example
LinkDaisy UIButtonwith Color Modifier
<Link href="/" className="btn btn-primary"> Home </Link>- Here are a few Daisy UI button color modifications to pick from with an example picture and several more can be found in Daisy UI's documentation.
btn-neutralbtn-primarybtn-secondarybtn-accentbtn-ghostbtn-link

- Example
- Increase the navigation button font size using a Tailwind CSS utility class. Style your
Linkelements with thetext-xlTailwind CSS utility class.- Example
LinkDaisy UIButtonwith larger text
<Link href="/" className="btn btn-primary text-xl"> Home </Link>- Note: above you were able to use both Daisy UI and Tailwind CSS classes to style an HTML element. This is a great example of how Daisy UI and Tailwind CSS can be used hand in hand to style an application.
- Example
Now, your navigation bar should look something like below except with your color of choice. This example uses
btn-primaryas the color modifier and the example in thesolutiondirectory usesbtn-ghost.
- Transform your Next.JS
-
Challenge
Styling the Navigation Bar
Styling the Navigation Bar
In the previous step, you styled the navigation buttons. Continue to work in
app/(ui)/components/nav-bar.jsxand follow the steps below to transform the existing HTMLnavelement to be aNavbarDaisy UI component with Tailwind CSS custom styling.- Transform the existing HTML
navelement to be a Daisy UINavbarby adding the Daisy UInavbarclass.- Example Daisy UI
Navbar
<nav className="navbar"> ... </nav>- Note: The application navigation bar will now look something like the picture below. You can note the left padding that was introduced when the navigation bar because a Daisy UI navigation component.

- Example Daisy UI
- Use Tailwind CSS to color the background of the navigation bar so the bar stands out on the webpage. Add a Tailwind CSS background color class of your choosing to the nav element.
- Example Daisy UI
Navbarwith a blue background
<nav className="navbar bg-sky-200"> ... </nav>- Note: Tailwind CSS is built with a lot of background color options that can be added to any HTML element using their corresponding class name. All the available background colors Tailwind offers can be found here.
- Note: Your navigation bar should look something like the picture below after completing this step. The example below uses
bg-sky-200as its background color and the navigation bar in thesolutiondirectory usesbg-emerald-500as its background color.
- Example Daisy UI
- Transform the existing HTML
-
Challenge
Styling the Expenses Table
Styling the Expenses Table
When you visit the
Expensespage on the application, you will be greeted with a table that is not styled. It should look like:
In
app/(ui)/expenses/page.jsx, follow the steps below to style the existing table by transforming it into a Daisy UITablecomponent that has a body with a white background.-
Transform the existing HTML
tableelement to be a Daisy UITablecomponent by styling the element with Daisy UI'stableclass.- Example Daisy UI
TableComponent
<table className="table"> ... </table>- Note: Refresh the expenses page, and the table should now look like:

- Example Daisy UI
-
Style the table body to have a white background color (use the
bg-whiteclass provided by Tailwind CSS).- Example Table Body with a White Background
<tbody className="bg-white"> ... </tbody>- Note: The white background color is different than the Daisy UI
Cardcomponent the table rests on. This is what makes the table body stand out on the card. - Note: Your expenses page should now look like:

-
-
Challenge
Add a Basic Dialog to the Expenses Page
Add a Basic Dialog to the Expenses Page
Follow the steps below to add a Daisy UI
Modalcomponent to theServerActionClientComponentAddTransactionFormcomponent available atapp/(ui)/components/server-action-client-component-add-transaction-form.jsx.- In the top
divelement above theformelement, add a newdialogHTML element that would display the placeholder text, "Hello".- Example Dialog Element
<dialog>Hello</dialog> - Label the
idattribute of this newdialogelement to be"createExpenseModal". Thisidmay seen robust now, but in the next step of this lab this modal be used to create a new expense and theidwill be fitting.- Example Dialog Element with an Id
<dialog id="createExpenseModal">Hello</dialog>- Note: When you look at the Expenses page, nothing should be different because the dialog you just added has no way to appear.
- In the
ServerActionClientComponentAddTransactionFormcomponent, add a new Daisy UIButton. Have the button reads "Create" since in the next step of the lab this button will serve to start the expense creation process.- Example Create Button
<button className="btn"> <p>Create</p> </button> - Style the button with any Daisy UI color modifier like you have done in previous steps.
- Note: the
solutiondirectory uses thebtn-accentcolor modifier.
- Note: the
- Style the button with Tailwind CSS
marginclasses andflexclasses until you are happy with the location of the button on the expenses page.- Note: the
solutiondirectory styles the create expenses button with the following Tailwind CSS utility classes:my-2 mr-4 flex flex-row.my-2adds a top and bottom margin of0.5rem, or8pxandmr-4applies a margin to only the right of the button. The other classes allow the button to be a part of a flexible layout and align itself horizontally.
- Note: the
- Style the button's
ptag with Tailwind CSS utility classes until you are happy with the font and text details.- Note: The
solutiondirectory styles theptag with the following classes:font-sans text-sm text-white.
- Note: The
- Program the button open the basic dialog.
-
Hint: You need to add an
onClickmethod that callsdocument.getElementById("createExpenseModal").showModal(). This will show the dialog when the create button is clicked. -
Note: The form on the expenses page may now look something like before clicking
Create:
-
Note: You should see a dialog that says "Hello" after clicking
Create, and it should look something like:
-
Note: You will not be able to perform any actions on the website until you close the dialog which is currently not implemented
-
- Inside the dialog, add a Daisy UI
Buttonto close it.- Hint: Inside the dialog next to the "Hello" text, add a Daisy UI
Buttonthat callsdocument.getElementById("createExpenseModal").close();when clicked. - Note: When the dialog is open, it should now look something like the picture below and close when you click the
Close.
- Hint: Inside the dialog next to the "Hello" text, add a Daisy UI
Example of a Styled Create Button that Opens a Dialog
<button className="my-2 mr-4 flex flex-row btn btn-accent" onClick={() => document.getElementById("createExpenseModal").showModal() } > <p className="font-sans text-sm text-white">Create</p> </button>Example of a Dialog with a Close Button
<dialog id="createExpenseModal"> Hello <button className="btn" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> </dialog> - In the top
-
Challenge
Transform the Basic Dialog into a Daisy UI Modal
Transform the Basic Dialog into a Daisy UI Modal Component
Now that you have a dialog that can be opened and closed, follow the steps below to transform the dialog into a Daisy UI
Modalcomponent.- Add Daisy UI's
modalclass to the dialog element.- Example of Daisy UI Modal Component
<dialog id="createExpenseModal" className="modal"> ... </dialog> - Style the dialog content to look like a modal using Daisy UI's
modal-boxandmodal-actionclasses.- Note: Daisy UI
Modals already have styling for amodal box(the container of the content that will go in the modal) and styling formodal actions(the buttons and forms that will perform modal actions like closing the modal and creating expenses).
- Inside the
dialogelement, wrapClosebutton in adivtag styled with themodal-actionclass. - Wrap the entire contents of the
dialog elementin anotherdivtag styled with themodal-boxclass.
- Note: Daisy UI
If you click
Create, your modal should now look like this:
Example Daisy UI Modal
<dialog id="createExpenseModal" className="modal"> <div className="modal-box"> Hello <div className="modal-action"> <button className="btn" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> </div> </div> </dialog> - Add Daisy UI's
-
Challenge
Move the Create Expense Form into the Basic Modal
Move the Create Expense Form into the Modal
In the previous lab step you transformed the basic dialog into a Daisy UI
Modal. Follow the steps below to move theCreate Expenseform into theModal.- Remove the
Modal's "Hello" text placeholder. - Copy the
formelement and and its contents into theModal'smodal boxsection.
Your modal should now look something like:

Example with Form in Modal Element
<dialog id="createExpenseModal" className="modal"> <div className="modal-box"> <form action={async (formData) => { const transactions = await createTypeTransaction(formData); if (transactionPath === "/income") { setTransactions(transactions); } }} id="createTransactionForm" > <input name="date" type="date" required /> <input name="amount" type="number" step="0.01" placeholder="10.00" required /> <input name="category" type="text" placeholder="Category" required /> <textarea name="notes" placeholder={"Notes"} /> <input name="type" type="text" placeholder={"expense"} hidden={!!transactionType} /> <button type="submit" className="btn float-right btn-accent font-sans text-sm text-white" > Create {transactionType ? transactionType : "Transaction"} </button> </form> <div className="modal-action"> <button className="btn" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> </div> </div> </dialog>
Close and Reset the Modal on Form Submission
Create an expense using the
Modalon theExpensespage. You will notice theModaldoes not close when submitting theform. Close theModalonformsubmission by following the step below.- Add
document.getElementById("createExpenseModal").close();to the bottom ofform'sactionmethod to close theModalupon creating an expense.
Create an expense again in the application and you will notice that the
Modalcloses uponformsubmission; however, if you start to create a second expense by reopening theModal, you will notice another problem that theform's data does not reset onformsubmission. Follow the step below to resetformdata onformsubmission.- The
form'sidiscreateTransactionForm, so find theformelement using theidandresetthe data as part of theform'saction.- Hint: Add
document.getElementById("createTransactionForm").reset();to the bottom ofform'sactionmethod to reset theModalupon creating an expense.
- Hint: Add
Example Form Element that Can Close and Reset the Modal
<form action={async (formData) => { const transactions = await createTypeTransaction(formData); if (transactionPath === "/income") { setTransactions(transactions); } document.getElementById("createExpenseModal").close(); document.getElementById("createTransactionForm").reset(); }} id="createTransactionForm" > ... </form>Lastly, on the application open the
Modal, fill out theform, and close theModalwithout submitting the form. Reopen theModaland you will notice that theform's data was notreset. Follow the steps below to address this.- Move the
Closebutton into theformelement underneath theform'screatebutton. - Set the
Closebutton'stypetoresetto clear theform's data when you close theModalwithout creating an expense.- Example of a
CloseButtonon aformthe resetsformdata when clicked
<button className="btn" type="reset" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> - Example of a
- Remove the
Modal'smodal-actionsection as it now is empty.
Example Create Expense Dialog After the Above Steps
<dialog id="createExpenseModal" className="modal"> <div className="modal-box"> <form action={async (formData) => { const transactions = await createTypeTransaction(formData); if (transactionPath === "/income") { setTransactions(transactions); } document.getElementById("createExpenseModal").close(); document.getElementById("createTransactionForm").reset(); }} id="createTransactionForm" > <input name="date" type="date" required /> <input name="amount" type="number" step="0.01" placeholder="10.00" required /> <input name="category" type="text" placeholder="Category" required /> <textarea name="notes" placeholder={"Notes"} /> <input name="type" type="text" placeholder={"expense"} hidden={!!transactionType} /> <button type="submit" className="btn float-right btn-accent font-sans text-sm text-white" > Create {transactionType ? transactionType : "Transaction"} </button> <button className="btn" type="reset" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> </form> </div> </dialog>You should now have a blank form whenever you create an expense or close the modal without creating an expense. Try it out in the web browser to verify.
- Remove the
-
Challenge
Tailwind CSS Forms
Configure the Application to Use Tailwind CSS Forms
In this step of the lab, you will update the create expense
formfrom the previous step to be aTailwind CSS Form.Tailwind CSS Formsare available as apluginand are not brought into a Tailwind CSS application by default. TheTailwind CSS Formspluginhas already been installed for you, but the application is not yet configured to use them. Configure the application to useTailwind CSS Formsby following the instruction below.-
Adding
@tailwindcss/formsto thepluginlist intailwind.config.js.- The application
pluginconfiguration should now look something like below now as you added the Daisy UIpluginin a previous lab step:
module.exports = { … plugins: [require('daisyui'), require("@tailwindcss/forms")], }
- The application
Update the Create Expense Form to be a Tailwind CSS Form
Transforming the create expense
forminto aTailwind CSS Formis as simple as styling with Tailwind CSS. The table below provides some of the relevant class names based on the create expenseform'sinputtypes. Follow the instruction under the table to transform the create expenseformintoTailwind CSS Formand style the form.| Base | Class | | -------- | ------- | |
[type='text']|form-input| |[type='number']|form-input| |[type='date']|form-input| |textarea|form-textarea|- Add the correct class to each of the create expense
form'sinputs based based on theinput's type. - Style the create expense
form'sinputs using Tailwind CSS utility classes until you are happy with the design. Relevant classes may changepadding,border radius,margin, andwidth. You can reference Tailwind CSS documentation for more class ideas if you need to.- For reference, the
formin thesolutiondirectory applies the following classes to allforminputs:px-4 rounded mb-5 w-full.
- For reference, the
Your form should now look something like:

Example Tailwind CSS Form
<form action={async (formData) => { const transactions = await createTypeTransaction(formData); if (transactionPath === "/income") { setTransactions(transactions); } document.getElementById("createExpenseModal").close(); document.getElementById("createTransactionForm").reset(); }} id="createTransactionForm" className="w-full" > <input className="formInput px-4 rounded mb-5 w-full" name="date" type="date" required /> <input className="formInput px-4 rounded mb-5 w-full" name="amount" type="number" step="0.01" placeholder="10.00" required /> <input className="formInput px-4 rounded mb-5 w-full" name="category" type="text" placeholder="Category" required /> <textarea className="form-textarea px-4 pxy-3 rounded w-full" name="notes" placeholder={"Notes"} /> <input name="type" type="text" placeholder={"expense"} hidden={!!transactionType} className="formInput px-4 rounded mb-5 w-full" /> <button type="submit" className="btn float-right btn-accent font-sans text-sm text-white" > Create {transactionType ? transactionType : "Transaction"} </button> <button className="btn" type="reset" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> </form> -
-
Challenge
Duplication While Using Tailwind CSS
Duplication While Using Tailwind CSS
One of the largest concerns with Tailwind CSS is the potential for a lot of duplication. You will start this step by seeing how this issue can come to life while styling an application with Tailwind CSS. Follow the steps below to add
labels to the create expenseformand style the newlabels.- Add a label for each create expense
forminput.- Example Label for
date`input
<label htmlFor="date">Date</label> <input name="date" type="date" required />- Note: The
input'snameand thelabel'shtmlForproperties match.
- Example Label for
- Style each
labelwith the following set of Tailwind CSS utilitiy classes:block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2.- Note: Your form will now look like something like:

- Note: Your form will now look like something like:
Form with Labels Example
<form action={async (formData) => { const transactions = await createTypeTransaction(formData); if (transactionPath === "/income") { setTransactions(transactions); } document.getElementById("createExpenseModal").close(); document.getElementById("createTransactionForm").reset(); }} id="createTransactionForm" className="w-full" > <label className={formLabelTailwindCSS} htmlFor="date"> Date </label> <input className="formInput" name="date" type="date" required /> <label className={formLabelTailwindCSS} htmlFor="amount"> Amount </label> <input className="formInput" name="amount" type="number" step="0.01" placeholder="10.00" required /> <label className={formLabelTailwindCSS} htmlFor="category"> Catgeory </label> <input className="formInput" name="category" type="text" placeholder="Category" required /> <label className={formLabelTailwindCSS} htmlFor="notes"> Notes </label> <textarea className="form-textarea px-4 pxy-3 rounded w-full" name="notes" placeholder={"Notes"} /> <label className={classNames(formLabelTailwindCSS(), { invisible: !!transactionType, })} htmlFor="type" > Transaction Type </label> <input name="type" type="text" placeholder={"expense"} hidden={!!transactionType} className="formInput" /> <button type="submit" className="btn float-right btn-accent font-sans text-sm text-white" > Create {transactionType ? transactionType : "Transaction"} </button> <button className="btn" type="reset" onClick={() => { document.getElementById("createExpenseModal").close(); }} > Close </button> </form>Above, you added
formlabels that you wanted to be styled with all the same Tailwind CSS classes for design consistency. However, it might have felt tedious typing out the same classes for eachlabel. It is encouraged to see this duplication issue as part of your larger code setup instead of one brought to you by Tailwind CSS.
Address the Styling Duplication Introduced Above and Examine Other Ways the Solution Addresses Styling Duplication
You can address this Tailwind CSS
classNameduplication in a few different ways.- You can extract a method that simply returns the class string and use that for the value of every label’s
classNameattribute. - You can extract a React component called something like
CreateExpenseFormLabelthat is a form label with styling and renders children and render that component in the form for each label. - Lastly, Tailwind CSS also uses the
@applydirective for duplication. In CSS files, you can use the@applydirective to use Tailwind classes in the definition of other CSS selectors.
Take some time to explore each of these options to avoid the label duplication introduced above. This is a self-guided exercise in this lab environment.
The
solutiondirectory contains a version of theappdirectory that has an example for each way to combat duplication above. Read more about the examples below to find them in thesolutiondirectory if you are interested in previewing them.- The
labelclass duplication introduced in this lab step is solved in thesolutiondirectory'sappusing an extracted method that returns the styling class string. - The
Homepage uses aHeadercomponent to display its title. ThisHeadercomponent could be reused on theIncomeandExpensespages to avoid duplication in styling. Look atsolution/app/page.js,solution/app/(ui)/components/header.jsx,solution/app/income/page,jsx, andsolution/app/expenses/page,jsx. - Just like you saw class duplication on the
formlabels in the step of the lab, in thesolution, there was also class duplication on theforminputs. Thesolutiondirectory'sappuses the@applydirective on a class insolution/app/global.cssto create a CSS class that is applied allforminputs.
- Add a label for each create expense
-
Challenge
Tailwind CSS Configuration
Tailwind CSS Configuration
The
tailwind.config.jsfile is where the configuration for Tailwind CSS resides. In previous steps, you have added plugins to the configuration of Tailwind CSS. A minimal configuration file looks like this:module.exports = { future: {}, purge: [], theme: { extend: {}, }, variants: {}, plugins: [], };Tailwind CSS considers each family of utilities to be a core plugin. Here is a list of all Tailwind CSS core plugins.
The
themeobject in Tailwind CSS configuration is helpful to define overarching design themes within your application. It can be used to customize core plugins. This can include overriding all of the core plugins options and extending those options.To override all of a core plugins options, you would provide a new set of values for it in
theme. Below is an example of overriding thescreenscore plugin. This example could be useful if you wanted to completely replace all of the screen breakpoints with custom or reworked ones.theme: { screens: { 'phone': '600px', 'laptop': '1280px', } }With the above theme you could start using
phoneandlaptopas Tailwind CSS utility classes.If you did not want to override all of a core plugin's values, you can keep the existing values and extend that core plugin.
The configuration file can also be used to exclude utility classes from being generated (if you needed it for performance reasons), configure variant prefixes (things like active, checked, and hover), and so much more. Tailwind CSS even has a way to prune off all the utility classes you did not use in an application by using the purge option in the configuration.
You may reference Tailwind’s documentation for configuration for more details.
Activity
The finance application you have been working on throughout this lab already references two custom colors on the
Homepage's transaction table. The application has not been able to use these custom colors because it has been unable to find the definition to them. TheHomepage's table currently looks like:
Extend the
colorcore plugin to include them.In
tailwind.config.js, add the code below to the configuration object.theme: { extend: { colors: { "light-red": "#f54248", "light-green": "#42f59b" } }, },The home page's table should now look like:

For reference, the transaction table now highlights expense rows with a red color and income rows with a green color. You added the custom red and green colors to the configuration.
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.