Download Next.js 13 Tutorial Subtitles – Learn App Router with TypeScript
Next js Tutorial for Beginners | Nextjs 13 (App Router) with TypeScript
Programming with Mosh
SRT - Most compatible format for video players (VLC, media players, video editors)
VTT - Web Video Text Tracks for HTML5 video and browsers
TXT - Plain text with timestamps for easy reading and editing
Scroll to view all subtitles
Welcome to the ultimate Next.js course.
In this course, you will learn
everything you need to know about
Next.js from the basics to more advanced
concepts. So, by the end of the course,
you'll be able to confidently build fast
and scalable applications with Next.js.
If you have been searching for a
comprehensive, easy-to-follow,
well-organized, and practical course
that takes you from zero to hero, this
is the right Next.js course for you. You
don't need any prior knowledge of
Next.js to get started. Everything you
need is right here, so you won't need to
jump back and forth between random
tutorials.
But, here's the catch. Unlike other
courses, we're not just building a dummy
app. We'll be building a beautiful,
full-stack, production-grade app for
tracking issues. An app complete with
all the features and UI patterns you
would expect in modern applications.
On the home page, we have this beautiful
dashboard that displays the latest
issues and their status. And all of this
data is stored in a MySQL database. We
can go to the issues page, we can filter
issues,
sort them,
and go to different pages.
We can click on an issue to see more
details.
We can assign an issue to a user. So,
here we have full authentication and
authorization.
We can edit an issue.
And here we have this beautiful markdown
editor.
We can also delete an issue, and here we
get this confirmation dialog box.
We'll be building this application using
a cutting-edge stack.
Next.js 13, Tailwind, Radix UI, Prisma,
React Query, React Hook Forms, Zod, and
more. And don't worry if some of these
tools are alien to you. Just like my
other courses, I will walk you through
each one, explaining the what, the why,
and the how. So, if you follow along,
you will master Next.js and will be able
to build full-stack applications with
confidence. I'm Mosh Hamedani, a
software engineer with over 20 years of
experience, and I've taught millions how
to code and become professional software
engineers through my YouTube channel and
online school codewithmosh.com.
If you're new here, make sure to
subscribe as I upload new videos all the
time. Now, let's jump in and get
started.
All right. So, what exactly do you need
to know to take this course? Well, to
take this course, you don't need any
prior knowledge of Next.js because I'm
going to teach you everything from the
ground up. However, you need to have
basic familiarity with React and
TypeScript because Next.js is a React
framework, and if you don't know React,
you're not really the right student for
this course.
Now, if you want to learn React, I have
a great tutorial on my YouTube channel.
The link is below this video. I also
have a comprehensive course that goes
way beyond that. It teaches you
everything you need to know to build
modern applications with React 18 and
TypeScript. The full course is 14 hours
divided into two parts, so you can
easily finish each part. In this course,
you will learn how to build this
beautiful application for discovering
video games. Here we have all the common
UI patterns you see in real applications
like filtering, sorting, infinite
scrolls, and so on.
Again, in case you're interested, the
link is below this video.
Welcome back to our Next.js course. In
this section, we'll be talking about the
fundamentals of Next.js.
First, I'll explain what exactly Next.js
is and why is it so popular. Shortly
after, we'll set up our development
environment and create our first Next.js
project. From there, we'll talk about
some foundational concepts such as
client and server components, data
fetching, caching, as well as static and
dynamic rendering. This section is a
great introduction to Next.js, so let's
jump in and get started.
So, you might be wondering, what is this
Next.js thing everyone is talking about
and why should I bother with it? Well,
Next.js is an incredibly powerful
framework for building fast and search
engine friendly applications. It's built
on top of React, so everything you have
learned about React is still relevant.
But, Next.js takes web development to
the next level. While React is just a
library for creating interactive user
interfaces, Next.js is a comprehensive
framework.
Think of a framework as a collection of
libraries, tools, and conventions that
streamline application development.
For instance, Next.js includes its own
routing library, so we don't need to use
a separate library like React Router.
In terms of tooling, it comes with a
compiler for transforming and minifying
our JavaScript code, a command-line
interface for building and starting our
application, and a Node.js runtime.
Now, you might wonder, what exactly is a
Node.js runtime? Well, there are two
main ways we can execute JavaScript
code. Within a web browser on the client
side, or within a Node.js runtime on the
server. So, a Node.js runtime is just a
fancy term for a program that can
execute JavaScript code. So, Next.js
comes with a Node.js runtime, and this
allows us to do some really cool things.
The first thing is that we can do
full-stack development. So, we can write
both the front-end and back-end code
within the same Next.js project. The
back-end code gets executed within the
Node.js runtime, and the front-end code
gets bundled and sent to the client for
execution within a web browser.
In contrast, when building applications
with React, we have to maintain a
separate back-end project in a
potentially different programming
language.
This Node.js runtime also allows us to
render our components on the server and
send their content to the client. This
technique is called server-side
rendering or SSR, and can make our
applications faster and more search
engine friendly.
We'll talk about it in detail later in
the course.
But, wait, there's more. With Next.js,
we can pre-render certain pages and
components that have static data when we
build our application.
We just render them once and serve them
whenever they're needed.
This technique is called static site
generation and can make our applications
super fast.
So, in a nutshell, Next.js is a
framework for building super fast and
search engine friendly applications.
All right. Now, let's talk about setting
up our development environment. To run
Next.js, you should have Node version
16.8 or higher.
So, head over to nodejs.org and download
the latest version.
Now, in this course, I will be using VS
Code as my editor, just like my other
courses. You're welcome to use your
preferred editor, but I encourage you to
use VS Code because along the way, I'll
be sharing a lot of tips and techniques
for writing code fast.
So, you can get VS Code from
code.visualstudio.com.
Now, here in VS Code window, let's talk
about the extensions I'm going to use in
this course.
So, in this panel, search for
ES7.
All right. Look at this extension.
ES7 plus React, Redux, and React Native.
This extension gives us a bunch of code
snippets, so we can quickly and easily
generate React components.
The next extension is TypeScript.
It's this one here.
JavaScript and TypeScript Nightly.
And the last one is
Tailwind CSS
IntelliSense.
Now, if you have never worked with
Tailwind before, don't worry. It's super
easy, and I'm going to hold your hands
through the entire course.
All right. To create our first Next.js
project, open up a terminal window and
run NPX create-next-app
@ You can use the latest version, but in
this course, I'm going to use version
13.4.
So, I strongly recommend you to use the
same version, so you don't have any
difficulties going through the course.
Let's go ahead.
Now, it's asking if you want to install
this package, create-next-app version
13.4.13.
Let's proceed.
All right. Now, it's going to ask us a
bunch of questions about our new
project. The first question is the name
of our project. I'm going to use
next-app.
The next question is if you want to use
TypeScript in this project. The default
answer is yes, so let's press enter to
accept it. The next question is about
using ESLint, which is a common code
analysis tool that we can use to find
common errors like syntax errors,
formatting issues, and so on. Again,
we're going to accept the default value,
which is yes.
The next question is about using
Tailwind CSS. One more time, we're going
to accept yes. The next question is
about using the source directory. A lot
of Next.js projects don't use the source
directory, so I'm going to select no
here.
The next question is about using the new
app router. I'm going to talk about this
later in this section, but very briefly,
in Next.js 13, we have two types of
routers. We have the new app router and
the legacy pages router. In this course,
we're going to use the new app router.
So, let's select yes.
The last question is about customizing
the default import alias. We're going to
select no.
All right. Now, it's going to install
all these dependencies, so you see we
have React, React DOM, Next, TypeScript,
and so on.
All right. All of dependencies are
installed. So, now let's go into this
folder
and run npm run dev.
This starts at development server on
port 3000. So, let's control and click
on this link.
And this confirms that our first Next.js
project is up and running.
Let's talk about the key files and
folders in this project. So, at the top
we have the app folder or this is also
called the app router. This is the
container for our routing system. So, in
Next.js our router is based on the file
system. So, unlike React router, we
don't have to configure our routes and
map them to our components. We can
simply create files and folders to
represent our routes. We'll talk about
them in the next lesson. So, in the app
folder we have a favicon. We have our
global CSS file.
A layout file, which is a basic React
component that returns
an HTML and body element. This
represents the common layout for our
pages.
Now, inside the body element we have
children, which is replaced by a page
dynamically at runtime depending on
where the user is in our application.
Now, in this folder we also have a page
file, page.tsx.
This represent our home page. Now, for
this demo, let's delete everything here
and
replace it
with a simple markup.
So, we're going to return a main
element.
Inside main we want to add an h1 and say
hello world.
Now, back to the browser.
Here we have fast refresh. So, anytime
we make any changes to our TypeScript or
CSS files, the changes are reflected
immediately. Now, here we have a bit of
styling issue because there is a
gradient, a linear gradient applied to
the body element.
So, let's go to our global CSS file.
Down the bottom,
look at the styles applied to the body
element.
The background attribute is set to a
linear gradient and that is why we have
this weird style here.
So, simply remove the background
attribute and
the issue goes away. Beautiful. Now, I
want to apply a padding here so the
content is not so close to the edges of
the screen.
So, let's set padding to
1 rem.
Okay?
That is better.
So, we're done with the app folder.
Now, in this project,
after the app folder, we have the public
folder. This is where we can put our
public assets like images. In this case,
we have two SVG files here, which are
vector graphics. One is Next, the other
is Vercel, which is the company that has
created Next.js.
Now, in the root we have a bunch of
configuration files.
We have one for ESLint, another for
Next, PostCSS, Tailwind, and TypeScript.
For the most part, we don't have to
touch these configuration files, but if
the situation changes in the future,
we'll come back and revisit them.
All right, I told you that routing in
Next.js is based on the file system. So,
here in the app folder,
we can create a new folder
called users.
Now, to make this publicly accessible,
here we should add a page file
in this folder. So, page.
Now, the extension can be JS, JSX, or
TSX for TypeScript. In this course, we
use TypeScript, so I'm going to go with
TSX.
Now, make sure to name this file
correctly, page in lower case, because
this is one of the conventions that
Next.js looks for.
So, the routing system in Next.js is
based on convention, not configuration.
Okay?
So, here we have a page file.
Now, in this page file, we should export
a React component that will be rendered
when the user is at this location,
/users.
Earlier we installed a very useful
extension in VS Code. With that
extension, we can generate a React
component using this shortcut, r a f c
e. That is short for React arrow
function component with an export. Now,
the way I remember this is rafce. Okay?
So, let's generate it. Beautiful. Now,
here we have multiple cursors activated,
so we can rename this component to
something more meaningful like users
page.
The name we assign here doesn't really
matter in terms of routing. This is just
for better organization of our code.
Okay?
Now, let's press escape to deactivate
multiple cursors.
So, back to the browser. Now, let's go
to /users
and here's our new users page.
Beautiful.
Now, one thing you need to know about
this routing system is that if you add
any other files in this folder, let's
say test.css,
this file is not going to be accessible.
So, if you go to /users/test.css,
look, we get this not found page. So,
this is how the new app router is
different from the old pages router. In
the pages router, if you put any files
in this folders, those files would be
publicly accessible, but this is not the
case with the new router. Okay?
So, let's delete this file.
Now, here we can also create nested
routes. So, inside the users folder,
we can add a new folder called new.
And in this folder we add
a new page file. So, page.tsx.
One more time, let's create a React
component
and we're going to call this new user
page.
Good. So, now we can go to users/new
and see this new page. Beautiful.
Now, let's talk about navigation. So,
we're going to go back to our home page.
So, here we press command and P on Mac
or control and P on Windows
to look up files by their name.
If we type page, we can see all our page
files. So, the first item is our home
page. This is the one we're looking for.
Now, on this page, let's add
an anchor.
So, here we add
an anchor. We set href to /users
and give it a label like users.
Now, there is a problem with this way of
implementing navigation. Let me show
you.
So, let's go back to our home page.
All right.
Now, I'm going to open up dev tools.
Here in the network tab,
look at all the requests sent to the
server.
The first one is our HTML document. The
second one is a font. The third one is a
CSS file. And after that, we have a
bunch of JavaScript files.
Now, I'm going to clear this list.
Look what happens when we click on the
users link.
Let's go back to the network tab. Look,
all these resources are re-downloaded.
This is not the optimal way to implement
navigation because in a real
application, we probably have a
navigation bar on the top, a side panel
on the left. So, as the user navigates
from one page to another, we don't want
to reload all these repetitive parts. We
only want to replace the content area,
right?
This is where we use the link component
in Next.js. So, back to our code.
We're going to replace this anchor
with the link component that is defined
in next/link
library.
Okay? Let's replace it here as well.
Good.
Now, back to our home page.
Once again, I'm going to bring up the
network tab
and clear this list.
Now, look what happens when we click on
the users link.
Look, we only have two requests and
these requests are for downloading the
content of the users page. So, we're not
re-downloading a font, a CSS file, and a
bunch of JavaScript files.
This is what we call client-side
navigation. Now, there's more to
navigation. We have a comprehensive
section about this topic later in the
course. This was just a basic overview.
In Next.js projects, we have two
environments where we can render our
components and generate HTML markup.
Either on the client within a web
browser or on the server within a
Node.js runtime. Rendering components on
the client is similar to how React
applications work. We refer to this
technique as client-side rendering or
CSR.
On the flip side, we have server-side
rendering or SSR, where components are
rendered on the server. So, what are the
differences? Well,
with client-side rendering, we have to
bundle all our components and send them
to the client for rendering. This means
as our application grows, so does our
bundle size because it must contain all
of our components. Now, the larger the
bundle, the more memory we need on the
client to load all these components. So,
this approach is resource heavy.
The other problem is that search engine
bots, which are machines that browse and
index our websites, can't view our
content because they can't execute
JavaScript code, so they cannot render
our components like a web browser.
And last but not least, any sensitive
data we have in our components or their
dependencies like API keys will be
exposed to the client. Now, if we render
our components on the server, we can get
rid of all these problems. We only send
the essential components to the client
and prevent our bundle from becoming
unnecessarily large. Also, because the
server handles most of the rendering, we
need less resources on the client. Plus,
because rendering is done on the server
and we send the actual content to the
client, search engine bots can view and
index our pages. And finally, we can
keep sensitive data like API keys on the
server.
So, these are all the great benefits of
server-side rendering.
However, with server-side rendering, we
lose interactivity.
So, server components, which are
components that are rendered on the
server, cannot listen to browser events
like click, change, submit, and so on.
They cannot access browser APIs like the
local storage. They cannot maintain
state or use effects. These
functionalities are only available in
client components.
So, in real-world applications, we often
use a mixture of server and client
components. We should default to server
components and use client components
only when we absolutely need them.
Here is an example. Let's imagine we
want to build a page to show a list of
products. To build this page, we
probably need several components like
navbar, sidebar, product list, product
card, pagination, and footer.
Now, in standard React applications, we
have to package all these components and
send them to the client for rendering.
But in Next.js, we can keep all these
components on the server and minimize
the bundle size. There is just one
exception.
To add a product to a shopping cart, we
need to handle the click event of a
button. Typically, we implement this
functionality in the product card
component. So, we have to make it a
client component. That's one option, but
there's a better way.
We can keep this component on the server
and do most of the rendering there, and
instead extract a small component that
only contains the add button.
With this change, we only ship a tiny
component to the client and keep
everything else on the server. Let's see
this in action.
Back to our project. In Next.js, all
components inside the app folder are
server components by default. So, that
means all the pages we have created so
far, these are server components and are
rendered on the server. Let me show you.
So, back to the browser. Let's bring up
the network tab and
look at the first request.
This is the HTML document that we get
from the back end. So, look. We have our
content here. We have our hello world
and the users link. This is exactly what
search engine bots see when they browse
our website. In contrast, if we used
client-side rendering, which is how
standard React applications work, search
engine bots wouldn't be able to see our
content. They would see a blank page
because all components, all the content
is rendered on the client. Okay?
So,
back to our project. All components
inside the app folder are server
components by default. Now, if you have
worked with Next.js before, I should
mention that the pages router doesn't
support server components. So, going
forward, you should stop using it and
switch to the new app router. Okay?
Now, let's create
a new folder here
called components.
Earlier, I told you that this folder is
not publicly accessible unless we add a
page file inside it. So, that means we
can colocate our project files like our
components and other building blocks
with our pages. We can put them next to
each other, and this is perfectly fine.
So, here in the components folder, let's
add
a new file called product card.tsx.
Here, we create a basic React component.
Now, earlier, I told you that server
components cannot have interactivity.
So, they cannot handle browser events
like click, change, and so on.
So, that means if we add
a button here
and handle the click event
we get a runtime error. Let me show you.
So, let's pass a basic arrow function
and log something on the console.
And we set the label to add to cart.
Now, let's add this component to our
home page.
So, we go to our first page file
and add our new product card component.
Now, back to the browser. Look, we got
an error saying event handlers cannot be
passed to client component props.
If you need interactivity, consider
converting part of this to a client
component.
Like here, we have two options. One
option is to make this entire component
a client component. So, we go to the top
and use the client directive. So, in
quotes, we type use client. That's all
we have to do.
With this, we tell the Next.js compiler
to include this file or this component
in our JavaScript bundle.
And that means if this component is
dependent on other components, those
components will automatically become
client components and will be included
in our JavaScript bundle. So, we don't
have to repeat this directive on every
client component. Okay?
So, here's one option. Now, if you go
back to the browser
the error is gone. But there is a better
way.
To make our applications faster and more
search engine friendly, we want to
render our components on the server as
much as possible and use client
components only when absolutely
necessary. So, here
our product card could have some complex
markup. We want to render all that
markup on the server and move this
button to the client.
So, I'm going to extract this button and
put it inside a separate component.
So,
here in the components folder, let's add
a new file
add to cart.
Again, we create a basic React
component. On the top
we use the client directive and then we
move
this button to our new component.
Like this.
Okay? So, now we have a client component
and we're going to use this in our
product card.
Okay?
With this, we can remove use client from
this file. So, this component will be
rendered on the server. And that means
where we have a client component, in
this case, where we have this button,
there's going to be a hole or a slot
where React will later inject our client
component. Okay?
Now, if you go back to the home page,
again, we don't see any errors. So, this
is how we can create and use client and
server components.
Hey guys, I hope you've been having fun
watching this tutorial. I just wanted to
mention that this tutorial is the first
hour of my complete Next.js course. So,
after you finish this, if you want to
learn more, I highly recommend you to
enroll in the full course because it's
much faster and easier than jumping
between a bunch of random, disconnected
tutorials here on YouTube. The full
course is 5 hours long and teaches you
everything you need to build full-stack
applications with Next.js. It also comes
with a certificate of completion and a
30-day money-back guarantee. So, if
you're not happy, ask for a full refund,
you get all your money back, no
questions asked. In case you're
interested, the link is below this
video.
Now, there are two ways we can fetch
data. We can fetch it on the client or
on the server. To fetch data on the
client, we typically use the state hook
to declare a state variable and the
effect hook to call the back end, get
the data, and put it into our state
variable. Now, in my React course, I
talked about React Query as a better
alternative to manually using the state
and effect hooks. But regardless of how
we fetch data, fetching data on the
client in client components has all the
problems we talked about in the previous
lesson. So, over time, our bundles would
get larger because we have to ship more
and more components to the client. Also,
this approach is resource intensive
because all the rendering is done on the
client. Plus, our content or our data is
not visible to search engines, and this
approach is less secure because our API
keys or any kind of sensitive data will
end up on the client. But there is one
extra problem. The problem is that with
this approach, there's always an extra
round trip to the back end. So, when a
React application loads, first the
browser downloads the HTML template as
well as the CSS and JavaScript files
from the back end. Then, it will send an
extra request to fetch data from the
back end. So, there's always an extra
round trip to the back end. Now, we can
fetch data in our server components and
get rid of all these problems. Let me
show you.
In this lesson, we're going to use JSON
Placeholder to get some dummy data into
our application. In case you are not
familiar with JSON Placeholder, it's a
fake API for getting some dummy data.
So, head over to
jsonplaceholder.typicode.com.
On this page, you will find various
endpoints for getting dummy data like a
list of posts, comments, albums, photos,
to-dos, and users.
In this lesson, we're going to get a
list of users into our application.
So, look. Each user object has a bunch
of properties like ID, name, username,
and so on.
So, back to our project
let's go
to the app folder and then open the
users folder and then go to this page.
Now, this is a server component, and in
server components, we can use the fetch
function that you are probably familiar
with.
This function is defined in browsers,
and with this, we can send HTTP requests
to the back end.
So, here we pass the URL of our
endpoint, which we grab from here.
So, copy
and paste it.
Now, this returns a promise, so we have
to await it
to get the response.
Now, because we're using await here, we
have to make this component async.
Now, this is the beauty of this
approach. With this approach, we don't
have to use a state variable, we don't
have to use the effect hook with zero
dependencies. There's no ceremony. We
just call fetch to get the data. And all
of this happens on the server. You'll
see that in a minute.
So, we get the response. Then we call
response.json.
This also returns a promise,
so we await it
to get the data, in this case,
our users.
Next, we map these users to a bunch of
list items, exactly like how we render
them in a React application.
So, for our markup, let's replace this
div with a fragment. Here we add an h1
called users.
Then we add an unordered list, and here
we map
these users.
We grab each user.
Now, if you type user. Look, we don't
see anything because the compiler
doesn't know about the type of these
user objects. So, if you hover our mouse
over this constant, look, the type of
this constant is any, which means we
don't know. It could be anything.
This is where we can use some TypeScript
magic to improve our code.
So, outside of this component,
we define an interface
or a type called user.
And here we say that each user has a
property called ID of type number.
It also has name of type string and so
on. We could list all the properties we
have here, but that is not necessary for
this lesson, so we're going to keep
things simple. So, with this interface,
we're defining the shape of our user
objects, okay?
Now, where we declare this constant,
we annotate it with its type, which is
user array.
Okay? With this,
when we type user.
we can see the properties of user
objects. So, this is the benefit of
using TypeScript. With TypeScript, we
get auto-completion when we're coding,
and also if we have any kind of errors
like typos, we can catch those errors at
build time, before we run and deploy our
application, okay?
So, here we're going to map each user to
a list item.
First, we give it a key,
which we set to user.id.
And here we render user.name.
That's all we had to do. So, our code is
simpler, there's no state and effect
hook here. Our bundle is going to be
smaller because this component will be
on the server.
Now, back to the browser, let's go to
the users page. Here's our users,
beautiful. Now, let's bring up the
network tab
and refresh the page.
So, take a look at the document that we
received from the back-end.
So, all our users are rendered right
here. This is because rendering is
happening on the server. In contrast, in
typical React applications or wherever
we use client-side rendering, the
browser initially gets a blank document.
Then it will call the back-end to fetch
the data and then render the content.
So, there's always an extra round trip
to the back-end, and our application is
not search engine friendly. So, to fetch
data, whenever possible, we should fetch
it in server components.
Fetching in server components has an
extra benefit, and that is caching. What
is caching? Well, the idea of caching is
to store data somewhere that is faster
to access.
Basically, there are three places where
we can get the data from. We can get it
from the memory, from the file system,
or from the network. Now, as we go down
this list, getting data becomes slower.
For example, getting data from the
network is always slower than getting it
from the file system. For this reason,
Next.js comes with a built-in data
cache.
So, whenever we use the fetch function
to get some data, Next.js will
automatically store the result in its
data cache, which is based on the file
system. So, the next time we need the
same piece of data, that next time we
hit the same URL, Next.js is not going
to go to JSON Placeholder, it's going to
get the data from its data cache, from
the file system. Of course, we have full
control over this caching behavior. If
you have data that changes frequently,
we can disable caching or treat data in
cache as fresh for a certain period of
time. Let me show you.
So, here when we call the fetch
function, we can pass a second argument,
which is an options object. Let me put
this on a new line, so you can see
clearly.
In this object, we can set cache to
no-store
to disable caching. That's one option,
and this is useful if you have data that
changes frequently. In those situations,
we always want to show fresh data to our
users, right?
The other option is to keep data fresh
for a certain period of time.
To do that, instead of setting cache to
no-store,
we set next to an object.
In this object, we can specify
configuration parameters that are
specific to Next.js.
So, here we can set revalidate to value
like 10,
and this means Next.js is going to run a
background job and get fresh data from
the back-end every 10 seconds. So, this
is how caching works in Next.js.
Now, one thing you need to know is that
this caching behavior is only
implemented in the fetch function. So,
if you use a third-party library like
Axios, you're not going to get this.
You're not going to get the data cache.
In Next.js, we have another performance
optimization technique called static
rendering or static site generation. The
idea of static rendering is that if you
have pages or components that have
static data, we can have Next.js render
them once when we build our application
for production. So, next time those
pages or components are needed, Next.js
is not going to re-render them. It's
going to get their payload or content
from its cache, which is based on the
file system. This is static rendering,
meaning rendering at build time. In
comparison, we have dynamic rendering,
which happens at request time. Let's see
this in action.
So, back to our users page, let's add a
timestamp above the list of users. So,
here we add a paragraph and render.
First, we create a new date object, and
then call toLocaleTimeString.
With this, we can see when this page was
rendered.
Now, back in the browser, let's refresh
a few times. So, look, the timestamp is
changing. This only happens in
development mode. But if we build this
application for production, you'll see
that the timestamp is not going to
change because Next.js will treat this
page as a static page. And here's the
reason.
Earlier, I told you that by default,
whenever we use the fetch function,
Next.js will cache the data. So, it
treats our data as static or unchanging
data. So, when rendering this page,
Next.js sees that this page has static
data, so it decides to render this page
statically at build time. But if we
disable caching, Next.js thinks the data
on this page is going to change, so it's
not going to render this page
statically, it's going to render it at
request time.
To see this action, let's go back to the
terminal window,
stop this process.
Now, earlier we used npm run dev to
start this application in our
development server. Now, to build this
for production, we run npm run build.
All right, here you can see all the
routes that are generated when we build
our application for production.
So, this is our root route or the home
page. We have a route for our favorite
icon.
We have one for the users page, another
for the users/new page, and so on.
Now, look at the icon before each of
these routes. Here, we only see circles.
Now, down here, you can see that a
circle means static. So, these pages are
automatically rendered as static HTML.
Now,
if you start this application in
production, which we can do by running
npm start,
and then go back to the browser,
let's refresh.
Look, the timestamp is not changing
because this page was rendered
statically at build time.
Now, back to this page, let's disable
caching and rebuild this application for
production.
So, as a second argument, we pass an
options object, and here we set cache to
no-store.
Okay?
Now, back to the terminal, let's stop
this process,
and rebuild the application.
Lovely. Now, look at the icon
before the users route. Instead of a
circle, we have a lambda. And down here,
you can see that lambda means rendering
on the server. So, server-side renders
at run time.
Now, let's start the application in
production.
Back to the browser, let's refresh.
Now, look, every time you refresh, the
timestamp changes.
Let's recap everything you have learned
about rendering. In Next.js, rendering
can happen on the client or on the
server. If it happens on the server, it
can happen at build time, which is
called static rendering, or at request
time, which is called dynamic rendering.
So, that brings us to the end of this
section. In the next section, we'll talk
about styling Next.js applications. So,
I will see you there.
Welcome back to our Next.js course. In
this section, we'll explore various ways
to style our applications and make them
beautiful.
We'll cover global styles, CSS modules,
Tailwind, and Daisy UI. So, let's jump
in and get started.
Earlier in the course, we briefly talked
about our global style sheet in the app
folder.
So, let's open up globals.css.
In this file, on the top, we have three
directives to import the base styles
from Tailwind. Now, we're going to talk
about Tailwind later in this section,
but very briefly, Tailwind is a very
popular CSS framework, okay?
Then after that, we have this root
selector. This is where we typically
define custom properties like foreground
RGB, and so on.
Then we have media prefers-color-scheme:
dark. With this CSS feature, which is
relatively new, we can detect if the
user is in the dark mode or not. If so,
you can see that the value of these
custom properties is overwritten.
Now, down here,
you can see that we have used the value
of this custom property as the color of
the body element. So, we are not using
background start and end RGB. They were
used earlier when we had a gradient on
our home page. So, before going further,
let's do a bit of cleanup here. I'm
going to delete these two lines, and
these two lines from here.
And also, let's go back to the terminal
and make sure
that we're running this application in
development, so anytime we make any
changes here, we can see the changes
immediately. So, npm run dev.
Good. Now, back to this file.
So, this is our global style sheet, and
we should use it for styles that are
truly global in our application, styles
that apply to all pages, like anything
to do with the body element, our
headings, our hyperlinks, and so on.
Anything that is specific to a page or a
component, we should implement it
somewhere else. So, one thing you
shouldn't do here is you shouldn't
define custom classes like user list,
because this only applies to a
particular component or page. With this
approach, as we build more and more
components, this global style sheet
grows really large and becomes
unmanageable. And more importantly, as
we change or delete our components,
we'll have to remember to come back and
do some cleanup here. Otherwise, over
time, we'll have a lot of dead styles in
this file. If you have been working with
CSS for a while, you know what I'm
talking about.
So, reserve this file for styles that
are truly global. For styles that are
specific to a page or a component, use
CSS modules or Tailwind, which we're
going to talk about next.
All right, let's talk about CSS modules.
A CSS module is a CSS file that is
scoped to a page or a component. It's a
way to prevent styles from clashing or
overriding each other. If you have been
working with CSS for a while, you know
that if you have the same class defined
in two different places in two different
style sheets, these classes can override
each other depending on how we import
these style sheet files. CSS modules aim
to solve that problem. Let's see how
they work.
So, here in the components folder,
we have a component called product card.
Now, let's say you want to create some
styles for this component. So, here we
add a new file.
We can call this file anything, but it's
better to call it the same as the
component, so product card. What matters
is that the extension has to be dot
module.css.
Okay?
Now, in this file or in this CSS module,
we can define classes that are scoped to
our product card component. So, let's
define a class called card.
And of course, we can define this class
somewhere else without worrying that
these classes would clash, okay?
So, here we can apply a padding of 1
rem,
and a border of 1 pixel solid
CCC.
Now, we go back to our component,
and import
this style sheet. So, we type import
styles
from current folder,
productcard.module.css.
The name we assign here doesn't matter,
but typically we go with styles, and
this will be a JavaScript object. So,
the classes that we define in this CSS
module will end up being properties of
that object.
So, here if we type styles,
we should see those properties, but I
don't know why IntelliSense is not
currently working for me, so I apologize
for that. So, here we should see the
classes we have defined like card, and
so on. And that means in CSS modules, we
cannot use hyphens
when naming these classes, like card
container, because this is not a valid
name for a JavaScript property. So, in
these files, always use the camel case
notation. So, we remove the hyphen and
make the first letter of the second word
uppercase, okay?
Now, let's just simplify things. We go
with card.
Back to our component.
So, we have this object.
Now,
on this div, we set class name to
we use our curly braces and set it to
styles.card.
Now, back to the browser.
Here on the home page, you can see the
style applied to our card. But, let me
show you something interesting.
Let's right-click here, and inspect this
in Chrome DevTools.
Here's our div. Look at the class name.
This is not the class that we created,
right? This is auto-generated. So, what
is happening here is that this project
uses a tool called PostCSS for
transforming our CSS class names. So,
back to our project.
Here in the root folder,
we have a file called postcss.config.js.
In this file, currently we have two
plugins. One is Tailwind, the other is
autoprefixer. Now, for the most part, we
don't have to touch this configuration
file, but if you're an advanced PostCSS
user, you know this is where you can
provide your custom configuration.
So, when building our application,
Next.js uses PostCSS to transform our
class names and generate unique class
names that don't clash. This is how CSS
modules work. Now, one last thing before
we finish this lesson.
Currently, I've put
the CSS file and the TypeScript file
next to each other. If you don't like
mixing up your CSS and TSX files, you
can group them in folders. So, here we
can create a folder
like product card.
This is a container for our component.
In this component, we can have a TSX
file and a CSS file, okay?
And of course, we can use the same
technique with our pages. So, we can use
CSS modules to define styles that are
local to a particular page.
All right, let's talk about Tailwind.
So, Tailwind is a very popular CSS
framework that uses the concept of
utility classes.
So, here on tailwindcss.com,
you can see that we have a bunch of
classes like flex,
pt-4, which is short for padding top
four, text center, and so on.
So, here we have a ton of small utility
classes, and we can combine them to
style our application.
Some people love it, some people hate
it. I have to confess that I also have a
love-hate relationship with Tailwind,
but I think I love it more than I hate
it. If you have never used it before, I
strongly encourage you to give it a
chance, because these days, a lot of
projects are built with Tailwind. So, if
you want to upgrade your skills and
expand your job opportunities, you
should have Tailwind in your skill set.
So, in Tailwind, we have a ton of small
utility classes.
For example, for controlling paddings,
we have a bunch of classes that start
with P, followed by a number, which can
be 1 2 3 4, and so on. The larger the
number, the more padding we'll have.
We also have px for applying horizontal
padding. This is the same as applying a
left and a right padding. We also have
py for vertical padding. We have pt for
padding top, pr for padding right, pb
for padding bottom, and pl for padding
left. Now, you don't have to memorize
any of this stuff. As you practice,
you'll get the hang of them pretty
quickly.
Now, for margins, we have similar
classes, but they start with M, followed
by a number, mx for horizontal margin,
my for vertical margin, and so on.
Now, for styling text, again, we have a
ton of classes. For example, for
controlling the size, we have text-xs,
which is extra small. We have text
small, text base, which is like the
regular size. We have text large, x
large, 2x large, and so on.
For applying colors, we have classes
that start with text, followed by a
color.
So, if you Google Tailwind color
palette,
on this page,
you can see the default color palette
that comes with Tailwind. So, we have
all these beautiful colors, and for the
most part, we don't need to customize
them. They just look great as they are,
but you can always customize these and
use colors that are specific to your
brand.
Now, look for example for sky, we have
various shades of blue that start with
50 and go all the way to 950. The larger
the number, the darker the color. You
will see an example of this later in
this video. Now, back to our slide. For
controlling the background color, we
have a bunch of classes that start with
BG followed by a color code. Now, for
controlling the thickness of font, we
have a bunch of classes like font thin,
font light, normal, medium, bold, and so
on. That's the idea of Tailwind. Now,
there are a lot more classes in Tailwind
that we can cover here, but our focus
here in this course is on Next.js and
not Tailwind. I just want to show you
the basics so you can learn the rest on
your own.
So, let's see these classes in action
and then I will explain why you may want
to use Tailwind.
So, back to our project.
Earlier we used the CSS module to style
our product card. Let's see how we can
use Tailwind instead of a CSS module to
style this component. So,
in this file, we don't need to import
our CSS module.
Instead, we can apply
Tailwind utility classes right here.
Now, in this lesson, I'm going to use a
different set of styles than the styles
we applied in our CSS module so you can
see more of Tailwind in action.
So, we're going to give this some
padding which I type P- Now, if you
press control and space, you can see all
the padding classes. So, we have P-0
which is equivalent to padding zero.
We have padding one which is equivalent
to 0.25 REM or 4 pixels. And as the
number increases, we get more padding.
So, this IntelliSense comes with the
extension that we installed at the
beginning of the course.
So, let's give this a padding of five.
A vertical margin
of five.
Now, I want to give it a background
color so we type BG-
Now, look again in IntelliSense, we can
see all the colors. I'm going to go with
sky-
400.
Now, to make the text white, here we
apply text- white.
We can make it large.
So, here we use text XL or 2XL, 3XL, and
so on.
Again, on the right side you can see the
actual size that is applied. So, for
text XL, font size is 1.25 REM or 20
pixels.
Now, here's the part that gets
interesting. Here we have pseudo
selectors like hover
and with this, we can apply styles when
we hover over this box or this div.
So, we can change the background color
to BG sky 600 or 500 to make it slightly
darker.
Now, back to the browser. Here's our
div. If you hover over it, you can see
the color changes.
So, this is how we style our
applications with Tailwind. Now, the
selling point of Tailwind is that we can
style our components right here in our
component file. We don't have to juggle
back and forth between a CSS file and a
component file. Everything is in one
place. Now, some people argue that this
violates the separation of concerns
principle, but I have to disagree with
that because the whole idea of
separation of concerns is organize our
code into distinct sections or modules,
each having a separate concern.
If you follow this principle, we'll have
more opportunities for reuse. But in
this case, this React component itself
is a module and defines the reuse
boundary. So, what we have inside this
boundary is purely implementation
detail. We can have markup with
JavaScript and style all next to each
other. What is inside is irrelevant to
the outside world as long as this
component or this module is reusable.
That's just what I think. If you
disagree or don't like using Tailwind,
that's totally fine. But again, if you
want to expand your job opportunities, I
highly encourage you to learn Tailwind
because it's in high demand these days.
But there's one more benefit to using
Tailwind and this is the reason I
personally love Tailwind. With Tailwind,
when we build our application, our final
CSS bundle will only have the utility
classes that we have used in our markup.
So, if tomorrow we delete this div, none
of these classes will be in our final
CSS bundle unless we have used them
somewhere else. So, with Tailwind, we
don't have to remember to clean up as we
change or delete our components. With
CSS modules, if we delete this
component, we have to remember to delete
the CSS file as well. Or, if we change
the structure here, we might still have
unused classes in our CSS module. So, we
have to remember to come back and clean
up. So, that's the selling point that
convinced me to start using Tailwind.
But on the flip side, I don't like that
over time, as our markup gets complex,
we'll have a lot of these classes and
the code is kind of hard to read, but
it's just a matter of getting used to
it. It's not terribly bad, but it's
something that put some people off early
on, but over time, I think the benefits
outweigh the downside.
All right, and let's talk about DaisyUI.
DaisyUI is a very popular component
library for Tailwind. It's kind of like
Bootstrap for Tailwind. So, if you head
over to daisyui.com,
you can see all these components.
For example, we have accordions, alerts,
we have breadcrumbs, buttons, cards,
carousel, chat bubbles, and so on. Very,
very useful. It's very easy to use, so
let's go
to the installation page.
First, we have to install
Daisy
as a development dependency. So, I'm
going to copy this line.
Now, back in VS Code, I've opened my
terminal window. You can open it from
terminal, new terminal.
Now, let's paste that.
Good. Next,
we should add Daisy as one of the
plugins of Tailwind. So, we should go to
Tailwind configuration file in the root
of our project. So, that is right here.
Currently, there are no plugins. So,
let's copy
this line and
paste it here.
That's literally all we have to do.
Now, let's see how we can use these
components. So, as an example,
we're going to look at the button
component.
So, here we have a bunch of classes like
BTN, BTN- neutral, BTN-primary,
secondary, and so on. Exactly like
Bootstrap. Under these classes use
Tailwind. So, instead of us manually
combining a bunch of small Tailwind
classes to create a button, we can just
use the button that comes with Daisy.
And of course, we can always customize
these buttons, okay?
So, to create a button,
look, we should have an example down
here. There you go. This is just a basic
button. We also have neutral, primary,
secondary, and so on.
So, back to our code.
Let's style this component that we
created earlier. Add to cart. So, here
we have a button.
We set class name to BTN, BTN-primary.
We don't have to import anything in this
file, okay?
Now, back to the home page. Here's what
we get. Let's remove this blue
background because it looks kind of odd.
So,
we're going to go back to
product card.tsx
and I'm going to remove all these
Tailwind classes.
Okay?
So, here's what we are left with. Now,
in Daisy, we have the concept of themes.
For example, if you look at this page,
themes,
you can see all the available themes.
Now, in this lesson, I'm going to use a
theme called winter. And you can always
preview these themes. So, on the top,
you can select them and see what your
application looks like. Here's the dark
mode. Here we have the cupcake theme,
and so on.
Now, to use a theme, there are two steps
we have to follow. First, we have to go
in Tailwind configuration file and add
this section for DaisyUI. So, here we
activate the themes we want to use.
So, let's copy
this section
and go back to tailwind.config.ts.
Right after plugins, we paste this.
So, we have DaisyUI. We have themes. I
don't want to use any of these. I only
want to use
the winter theme.
The second step is to apply this theme
on our HTML element. So, back in the
documentation, look, here we have a data
attribute for specifying the theme.
To do that, we have to go to our layout
file
because this is where we have our HTML
element. So, we set data-theme
to winter.
Now, back to our home page, our button
looks blue. Beautiful.
Now, let's go to the users page and
put these users inside a table. So,
let's go to the users page
and replace
this unordered list with a table. So, we
select this and press command and D on
Mac or control and D on Windows to
activate multiple cursors. Now, we can
change these two elements in one go. So,
we change it to a table.
Then, we press escape to deactivate
multiple cursors.
Now, inside this table, you want to have
a t head. Inside a t head, we want to
have a t r, and inside the t r, we want
to have two t h elements. Let's press
tab.
Here's our markup, beautiful.
Now, here we want to have two columns.
The first one is username, the second is
user email.
Now, after the t head element,
we should add a t body.
Then we move
mapping over users inside t body
and replace l i with t r. So, once
again, we press command and d on Mac or
control and d on Windows to change both
these elements in one go. So, let's
change it to t r.
Now, inside this t r,
we want to have two t h elements. So, t
h * 2.
Let me put it on a separate line.
Good. In the first t h, we want to
render user.name.
In the second, we want to render
user.email.
Now, currently, we don't have email in
the interface that we defined for our
users. That is why we get a compilation
error. So, this is another benefit of
using TypeScript. The TypeScript
compiler tells us about these issues
before we run or deploy our application.
We can catch these errors at compile
time or even while coding. So, up here,
we have the user interface.
Let's add an email property of type
string.
Now,
the error goes away. Lovely. So, back to
the browser.
Here's what we get. Now, let's apply a
couple of classes from Daisy to make
this table look a little bit nicer.
So, back to our code.
Here's our table.
We set class name to
table and table-
bordered.
And of course, you can find these in the
documentation for the table component in
DaisyUI.
Okay, this is much better.
Now, I made a mistake earlier. When
rendering these rows, I used the t h
element.
That is why they appear as bold, but we
should use t h only as the column of our
tables.
So, let's change all of these t h
elements to t d. Once again, we select
one of them
and we press command and d to select
more of them.
So, now we have four cursors. Let's
change all of them to t d.
Okay, here's what we get.
Now, we no longer need the time stamp,
so
let's remove it from here as well.
Good. So, we're done for now. In the
next section, we're going to talk about
routing and navigation in more detail.
Hey guys, I hope you've been having fun
watching this tutorial. I just wanted to
mention that this tutorial is the first
hour of my complete Next.js course. So,
after you finish this, if you want to
learn more, I highly recommend you to
enroll in the full course because it's
much faster and easier than jumping
between a bunch of random, disconnected
tutorials here on YouTube. The full
course is 5 hours long and teaches you
everything you need to build full stack
applications with Next.js. It also comes
with a certificate of completion and a
30-day money-back guarantee. So, if
you're not happy, ask for a full refund,
you get all your money back, no
questions asked. In case you're
interested, the link is below this
video.
Full transcript without timestamps
Welcome to the ultimate Next.js course. In this course, you will learn everything you need to know about Next.js from the basics to more advanced concepts. So, by the end of the course, you'll be able to confidently build fast and scalable applications with Next.js. If you have been searching for a comprehensive, easy-to-follow, well-organized, and practical course that takes you from zero to hero, this is the right Next.js course for you. You don't need any prior knowledge of Next.js to get started. Everything you need is right here, so you won't need to jump back and forth between random tutorials. But, here's the catch. Unlike other courses, we're not just building a dummy app. We'll be building a beautiful, full-stack, production-grade app for tracking issues. An app complete with all the features and UI patterns you would expect in modern applications. On the home page, we have this beautiful dashboard that displays the latest issues and their status. And all of this data is stored in a MySQL database. We can go to the issues page, we can filter issues, sort them, and go to different pages. We can click on an issue to see more details. We can assign an issue to a user. So, here we have full authentication and authorization. We can edit an issue. And here we have this beautiful markdown editor. We can also delete an issue, and here we get this confirmation dialog box. We'll be building this application using a cutting-edge stack. Next.js 13, Tailwind, Radix UI, Prisma, React Query, React Hook Forms, Zod, and more. And don't worry if some of these tools are alien to you. Just like my other courses, I will walk you through each one, explaining the what, the why, and the how. So, if you follow along, you will master Next.js and will be able to build full-stack applications with confidence. I'm Mosh Hamedani, a software engineer with over 20 years of experience, and I've taught millions how to code and become professional software engineers through my YouTube channel and online school codewithmosh.com. If you're new here, make sure to subscribe as I upload new videos all the time. Now, let's jump in and get started. All right. So, what exactly do you need to know to take this course? Well, to take this course, you don't need any prior knowledge of Next.js because I'm going to teach you everything from the ground up. However, you need to have basic familiarity with React and TypeScript because Next.js is a React framework, and if you don't know React, you're not really the right student for this course. Now, if you want to learn React, I have a great tutorial on my YouTube channel. The link is below this video. I also have a comprehensive course that goes way beyond that. It teaches you everything you need to know to build modern applications with React 18 and TypeScript. The full course is 14 hours divided into two parts, so you can easily finish each part. In this course, you will learn how to build this beautiful application for discovering video games. Here we have all the common UI patterns you see in real applications like filtering, sorting, infinite scrolls, and so on. Again, in case you're interested, the link is below this video. Welcome back to our Next.js course. In this section, we'll be talking about the fundamentals of Next.js. First, I'll explain what exactly Next.js is and why is it so popular. Shortly after, we'll set up our development environment and create our first Next.js project. From there, we'll talk about some foundational concepts such as client and server components, data fetching, caching, as well as static and dynamic rendering. This section is a great introduction to Next.js, so let's jump in and get started. So, you might be wondering, what is this Next.js thing everyone is talking about and why should I bother with it? Well, Next.js is an incredibly powerful framework for building fast and search engine friendly applications. It's built on top of React, so everything you have learned about React is still relevant. But, Next.js takes web development to the next level. While React is just a library for creating interactive user interfaces, Next.js is a comprehensive framework. Think of a framework as a collection of libraries, tools, and conventions that streamline application development. For instance, Next.js includes its own routing library, so we don't need to use a separate library like React Router. In terms of tooling, it comes with a compiler for transforming and minifying our JavaScript code, a command-line interface for building and starting our application, and a Node.js runtime. Now, you might wonder, what exactly is a Node.js runtime? Well, there are two main ways we can execute JavaScript code. Within a web browser on the client side, or within a Node.js runtime on the server. So, a Node.js runtime is just a fancy term for a program that can execute JavaScript code. So, Next.js comes with a Node.js runtime, and this allows us to do some really cool things. The first thing is that we can do full-stack development. So, we can write both the front-end and back-end code within the same Next.js project. The back-end code gets executed within the Node.js runtime, and the front-end code gets bundled and sent to the client for execution within a web browser. In contrast, when building applications with React, we have to maintain a separate back-end project in a potentially different programming language. This Node.js runtime also allows us to render our components on the server and send their content to the client. This technique is called server-side rendering or SSR, and can make our applications faster and more search engine friendly. We'll talk about it in detail later in the course. But, wait, there's more. With Next.js, we can pre-render certain pages and components that have static data when we build our application. We just render them once and serve them whenever they're needed. This technique is called static site generation and can make our applications super fast. So, in a nutshell, Next.js is a framework for building super fast and search engine friendly applications. All right. Now, let's talk about setting up our development environment. To run Next.js, you should have Node version 16.8 or higher. So, head over to nodejs.org and download the latest version. Now, in this course, I will be using VS Code as my editor, just like my other courses. You're welcome to use your preferred editor, but I encourage you to use VS Code because along the way, I'll be sharing a lot of tips and techniques for writing code fast. So, you can get VS Code from code.visualstudio.com. Now, here in VS Code window, let's talk about the extensions I'm going to use in this course. So, in this panel, search for ES7. All right. Look at this extension. ES7 plus React, Redux, and React Native. This extension gives us a bunch of code snippets, so we can quickly and easily generate React components. The next extension is TypeScript. It's this one here. JavaScript and TypeScript Nightly. And the last one is Tailwind CSS IntelliSense. Now, if you have never worked with Tailwind before, don't worry. It's super easy, and I'm going to hold your hands through the entire course. All right. To create our first Next.js project, open up a terminal window and run NPX create-next-app @ You can use the latest version, but in this course, I'm going to use version 13.4. So, I strongly recommend you to use the same version, so you don't have any difficulties going through the course. Let's go ahead. Now, it's asking if you want to install this package, create-next-app version 13.4.13. Let's proceed. All right. Now, it's going to ask us a bunch of questions about our new project. The first question is the name of our project. I'm going to use next-app. The next question is if you want to use TypeScript in this project. The default answer is yes, so let's press enter to accept it. The next question is about using ESLint, which is a common code analysis tool that we can use to find common errors like syntax errors, formatting issues, and so on. Again, we're going to accept the default value, which is yes. The next question is about using Tailwind CSS. One more time, we're going to accept yes. The next question is about using the source directory. A lot of Next.js projects don't use the source directory, so I'm going to select no here. The next question is about using the new app router. I'm going to talk about this later in this section, but very briefly, in Next.js 13, we have two types of routers. We have the new app router and the legacy pages router. In this course, we're going to use the new app router. So, let's select yes. The last question is about customizing the default import alias. We're going to select no. All right. Now, it's going to install all these dependencies, so you see we have React, React DOM, Next, TypeScript, and so on. All right. All of dependencies are installed. So, now let's go into this folder and run npm run dev. This starts at development server on port 3000. So, let's control and click on this link. And this confirms that our first Next.js project is up and running. Let's talk about the key files and folders in this project. So, at the top we have the app folder or this is also called the app router. This is the container for our routing system. So, in Next.js our router is based on the file system. So, unlike React router, we don't have to configure our routes and map them to our components. We can simply create files and folders to represent our routes. We'll talk about them in the next lesson. So, in the app folder we have a favicon. We have our global CSS file. A layout file, which is a basic React component that returns an HTML and body element. This represents the common layout for our pages. Now, inside the body element we have children, which is replaced by a page dynamically at runtime depending on where the user is in our application. Now, in this folder we also have a page file, page.tsx. This represent our home page. Now, for this demo, let's delete everything here and replace it with a simple markup. So, we're going to return a main element. Inside main we want to add an h1 and say hello world. Now, back to the browser. Here we have fast refresh. So, anytime we make any changes to our TypeScript or CSS files, the changes are reflected immediately. Now, here we have a bit of styling issue because there is a gradient, a linear gradient applied to the body element. So, let's go to our global CSS file. Down the bottom, look at the styles applied to the body element. The background attribute is set to a linear gradient and that is why we have this weird style here. So, simply remove the background attribute and the issue goes away. Beautiful. Now, I want to apply a padding here so the content is not so close to the edges of the screen. So, let's set padding to 1 rem. Okay? That is better. So, we're done with the app folder. Now, in this project, after the app folder, we have the public folder. This is where we can put our public assets like images. In this case, we have two SVG files here, which are vector graphics. One is Next, the other is Vercel, which is the company that has created Next.js. Now, in the root we have a bunch of configuration files. We have one for ESLint, another for Next, PostCSS, Tailwind, and TypeScript. For the most part, we don't have to touch these configuration files, but if the situation changes in the future, we'll come back and revisit them. All right, I told you that routing in Next.js is based on the file system. So, here in the app folder, we can create a new folder called users. Now, to make this publicly accessible, here we should add a page file in this folder. So, page. Now, the extension can be JS, JSX, or TSX for TypeScript. In this course, we use TypeScript, so I'm going to go with TSX. Now, make sure to name this file correctly, page in lower case, because this is one of the conventions that Next.js looks for. So, the routing system in Next.js is based on convention, not configuration. Okay? So, here we have a page file. Now, in this page file, we should export a React component that will be rendered when the user is at this location, /users. Earlier we installed a very useful extension in VS Code. With that extension, we can generate a React component using this shortcut, r a f c e. That is short for React arrow function component with an export. Now, the way I remember this is rafce. Okay? So, let's generate it. Beautiful. Now, here we have multiple cursors activated, so we can rename this component to something more meaningful like users page. The name we assign here doesn't really matter in terms of routing. This is just for better organization of our code. Okay? Now, let's press escape to deactivate multiple cursors. So, back to the browser. Now, let's go to /users and here's our new users page. Beautiful. Now, one thing you need to know about this routing system is that if you add any other files in this folder, let's say test.css, this file is not going to be accessible. So, if you go to /users/test.css, look, we get this not found page. So, this is how the new app router is different from the old pages router. In the pages router, if you put any files in this folders, those files would be publicly accessible, but this is not the case with the new router. Okay? So, let's delete this file. Now, here we can also create nested routes. So, inside the users folder, we can add a new folder called new. And in this folder we add a new page file. So, page.tsx. One more time, let's create a React component and we're going to call this new user page. Good. So, now we can go to users/new and see this new page. Beautiful. Now, let's talk about navigation. So, we're going to go back to our home page. So, here we press command and P on Mac or control and P on Windows to look up files by their name. If we type page, we can see all our page files. So, the first item is our home page. This is the one we're looking for. Now, on this page, let's add an anchor. So, here we add an anchor. We set href to /users and give it a label like users. Now, there is a problem with this way of implementing navigation. Let me show you. So, let's go back to our home page. All right. Now, I'm going to open up dev tools. Here in the network tab, look at all the requests sent to the server. The first one is our HTML document. The second one is a font. The third one is a CSS file. And after that, we have a bunch of JavaScript files. Now, I'm going to clear this list. Look what happens when we click on the users link. Let's go back to the network tab. Look, all these resources are re-downloaded. This is not the optimal way to implement navigation because in a real application, we probably have a navigation bar on the top, a side panel on the left. So, as the user navigates from one page to another, we don't want to reload all these repetitive parts. We only want to replace the content area, right? This is where we use the link component in Next.js. So, back to our code. We're going to replace this anchor with the link component that is defined in next/link library. Okay? Let's replace it here as well. Good. Now, back to our home page. Once again, I'm going to bring up the network tab and clear this list. Now, look what happens when we click on the users link. Look, we only have two requests and these requests are for downloading the content of the users page. So, we're not re-downloading a font, a CSS file, and a bunch of JavaScript files. This is what we call client-side navigation. Now, there's more to navigation. We have a comprehensive section about this topic later in the course. This was just a basic overview. In Next.js projects, we have two environments where we can render our components and generate HTML markup. Either on the client within a web browser or on the server within a Node.js runtime. Rendering components on the client is similar to how React applications work. We refer to this technique as client-side rendering or CSR. On the flip side, we have server-side rendering or SSR, where components are rendered on the server. So, what are the differences? Well, with client-side rendering, we have to bundle all our components and send them to the client for rendering. This means as our application grows, so does our bundle size because it must contain all of our components. Now, the larger the bundle, the more memory we need on the client to load all these components. So, this approach is resource heavy. The other problem is that search engine bots, which are machines that browse and index our websites, can't view our content because they can't execute JavaScript code, so they cannot render our components like a web browser. And last but not least, any sensitive data we have in our components or their dependencies like API keys will be exposed to the client. Now, if we render our components on the server, we can get rid of all these problems. We only send the essential components to the client and prevent our bundle from becoming unnecessarily large. Also, because the server handles most of the rendering, we need less resources on the client. Plus, because rendering is done on the server and we send the actual content to the client, search engine bots can view and index our pages. And finally, we can keep sensitive data like API keys on the server. So, these are all the great benefits of server-side rendering. However, with server-side rendering, we lose interactivity. So, server components, which are components that are rendered on the server, cannot listen to browser events like click, change, submit, and so on. They cannot access browser APIs like the local storage. They cannot maintain state or use effects. These functionalities are only available in client components. So, in real-world applications, we often use a mixture of server and client components. We should default to server components and use client components only when we absolutely need them. Here is an example. Let's imagine we want to build a page to show a list of products. To build this page, we probably need several components like navbar, sidebar, product list, product card, pagination, and footer. Now, in standard React applications, we have to package all these components and send them to the client for rendering. But in Next.js, we can keep all these components on the server and minimize the bundle size. There is just one exception. To add a product to a shopping cart, we need to handle the click event of a button. Typically, we implement this functionality in the product card component. So, we have to make it a client component. That's one option, but there's a better way. We can keep this component on the server and do most of the rendering there, and instead extract a small component that only contains the add button. With this change, we only ship a tiny component to the client and keep everything else on the server. Let's see this in action. Back to our project. In Next.js, all components inside the app folder are server components by default. So, that means all the pages we have created so far, these are server components and are rendered on the server. Let me show you. So, back to the browser. Let's bring up the network tab and look at the first request. This is the HTML document that we get from the back end. So, look. We have our content here. We have our hello world and the users link. This is exactly what search engine bots see when they browse our website. In contrast, if we used client-side rendering, which is how standard React applications work, search engine bots wouldn't be able to see our content. They would see a blank page because all components, all the content is rendered on the client. Okay? So, back to our project. All components inside the app folder are server components by default. Now, if you have worked with Next.js before, I should mention that the pages router doesn't support server components. So, going forward, you should stop using it and switch to the new app router. Okay? Now, let's create a new folder here called components. Earlier, I told you that this folder is not publicly accessible unless we add a page file inside it. So, that means we can colocate our project files like our components and other building blocks with our pages. We can put them next to each other, and this is perfectly fine. So, here in the components folder, let's add a new file called product card.tsx. Here, we create a basic React component. Now, earlier, I told you that server components cannot have interactivity. So, they cannot handle browser events like click, change, and so on. So, that means if we add a button here and handle the click event we get a runtime error. Let me show you. So, let's pass a basic arrow function and log something on the console. And we set the label to add to cart. Now, let's add this component to our home page. So, we go to our first page file and add our new product card component. Now, back to the browser. Look, we got an error saying event handlers cannot be passed to client component props. If you need interactivity, consider converting part of this to a client component. Like here, we have two options. One option is to make this entire component a client component. So, we go to the top and use the client directive. So, in quotes, we type use client. That's all we have to do. With this, we tell the Next.js compiler to include this file or this component in our JavaScript bundle. And that means if this component is dependent on other components, those components will automatically become client components and will be included in our JavaScript bundle. So, we don't have to repeat this directive on every client component. Okay? So, here's one option. Now, if you go back to the browser the error is gone. But there is a better way. To make our applications faster and more search engine friendly, we want to render our components on the server as much as possible and use client components only when absolutely necessary. So, here our product card could have some complex markup. We want to render all that markup on the server and move this button to the client. So, I'm going to extract this button and put it inside a separate component. So, here in the components folder, let's add a new file add to cart. Again, we create a basic React component. On the top we use the client directive and then we move this button to our new component. Like this. Okay? So, now we have a client component and we're going to use this in our product card. Okay? With this, we can remove use client from this file. So, this component will be rendered on the server. And that means where we have a client component, in this case, where we have this button, there's going to be a hole or a slot where React will later inject our client component. Okay? Now, if you go back to the home page, again, we don't see any errors. So, this is how we can create and use client and server components. Hey guys, I hope you've been having fun watching this tutorial. I just wanted to mention that this tutorial is the first hour of my complete Next.js course. So, after you finish this, if you want to learn more, I highly recommend you to enroll in the full course because it's much faster and easier than jumping between a bunch of random, disconnected tutorials here on YouTube. The full course is 5 hours long and teaches you everything you need to build full-stack applications with Next.js. It also comes with a certificate of completion and a 30-day money-back guarantee. So, if you're not happy, ask for a full refund, you get all your money back, no questions asked. In case you're interested, the link is below this video. Now, there are two ways we can fetch data. We can fetch it on the client or on the server. To fetch data on the client, we typically use the state hook to declare a state variable and the effect hook to call the back end, get the data, and put it into our state variable. Now, in my React course, I talked about React Query as a better alternative to manually using the state and effect hooks. But regardless of how we fetch data, fetching data on the client in client components has all the problems we talked about in the previous lesson. So, over time, our bundles would get larger because we have to ship more and more components to the client. Also, this approach is resource intensive because all the rendering is done on the client. Plus, our content or our data is not visible to search engines, and this approach is less secure because our API keys or any kind of sensitive data will end up on the client. But there is one extra problem. The problem is that with this approach, there's always an extra round trip to the back end. So, when a React application loads, first the browser downloads the HTML template as well as the CSS and JavaScript files from the back end. Then, it will send an extra request to fetch data from the back end. So, there's always an extra round trip to the back end. Now, we can fetch data in our server components and get rid of all these problems. Let me show you. In this lesson, we're going to use JSON Placeholder to get some dummy data into our application. In case you are not familiar with JSON Placeholder, it's a fake API for getting some dummy data. So, head over to jsonplaceholder.typicode.com. On this page, you will find various endpoints for getting dummy data like a list of posts, comments, albums, photos, to-dos, and users. In this lesson, we're going to get a list of users into our application. So, look. Each user object has a bunch of properties like ID, name, username, and so on. So, back to our project let's go to the app folder and then open the users folder and then go to this page. Now, this is a server component, and in server components, we can use the fetch function that you are probably familiar with. This function is defined in browsers, and with this, we can send HTTP requests to the back end. So, here we pass the URL of our endpoint, which we grab from here. So, copy and paste it. Now, this returns a promise, so we have to await it to get the response. Now, because we're using await here, we have to make this component async. Now, this is the beauty of this approach. With this approach, we don't have to use a state variable, we don't have to use the effect hook with zero dependencies. There's no ceremony. We just call fetch to get the data. And all of this happens on the server. You'll see that in a minute. So, we get the response. Then we call response.json. This also returns a promise, so we await it to get the data, in this case, our users. Next, we map these users to a bunch of list items, exactly like how we render them in a React application. So, for our markup, let's replace this div with a fragment. Here we add an h1 called users. Then we add an unordered list, and here we map these users. We grab each user. Now, if you type user. Look, we don't see anything because the compiler doesn't know about the type of these user objects. So, if you hover our mouse over this constant, look, the type of this constant is any, which means we don't know. It could be anything. This is where we can use some TypeScript magic to improve our code. So, outside of this component, we define an interface or a type called user. And here we say that each user has a property called ID of type number. It also has name of type string and so on. We could list all the properties we have here, but that is not necessary for this lesson, so we're going to keep things simple. So, with this interface, we're defining the shape of our user objects, okay? Now, where we declare this constant, we annotate it with its type, which is user array. Okay? With this, when we type user. we can see the properties of user objects. So, this is the benefit of using TypeScript. With TypeScript, we get auto-completion when we're coding, and also if we have any kind of errors like typos, we can catch those errors at build time, before we run and deploy our application, okay? So, here we're going to map each user to a list item. First, we give it a key, which we set to user.id. And here we render user.name. That's all we had to do. So, our code is simpler, there's no state and effect hook here. Our bundle is going to be smaller because this component will be on the server. Now, back to the browser, let's go to the users page. Here's our users, beautiful. Now, let's bring up the network tab and refresh the page. So, take a look at the document that we received from the back-end. So, all our users are rendered right here. This is because rendering is happening on the server. In contrast, in typical React applications or wherever we use client-side rendering, the browser initially gets a blank document. Then it will call the back-end to fetch the data and then render the content. So, there's always an extra round trip to the back-end, and our application is not search engine friendly. So, to fetch data, whenever possible, we should fetch it in server components. Fetching in server components has an extra benefit, and that is caching. What is caching? Well, the idea of caching is to store data somewhere that is faster to access. Basically, there are three places where we can get the data from. We can get it from the memory, from the file system, or from the network. Now, as we go down this list, getting data becomes slower. For example, getting data from the network is always slower than getting it from the file system. For this reason, Next.js comes with a built-in data cache. So, whenever we use the fetch function to get some data, Next.js will automatically store the result in its data cache, which is based on the file system. So, the next time we need the same piece of data, that next time we hit the same URL, Next.js is not going to go to JSON Placeholder, it's going to get the data from its data cache, from the file system. Of course, we have full control over this caching behavior. If you have data that changes frequently, we can disable caching or treat data in cache as fresh for a certain period of time. Let me show you. So, here when we call the fetch function, we can pass a second argument, which is an options object. Let me put this on a new line, so you can see clearly. In this object, we can set cache to no-store to disable caching. That's one option, and this is useful if you have data that changes frequently. In those situations, we always want to show fresh data to our users, right? The other option is to keep data fresh for a certain period of time. To do that, instead of setting cache to no-store, we set next to an object. In this object, we can specify configuration parameters that are specific to Next.js. So, here we can set revalidate to value like 10, and this means Next.js is going to run a background job and get fresh data from the back-end every 10 seconds. So, this is how caching works in Next.js. Now, one thing you need to know is that this caching behavior is only implemented in the fetch function. So, if you use a third-party library like Axios, you're not going to get this. You're not going to get the data cache. In Next.js, we have another performance optimization technique called static rendering or static site generation. The idea of static rendering is that if you have pages or components that have static data, we can have Next.js render them once when we build our application for production. So, next time those pages or components are needed, Next.js is not going to re-render them. It's going to get their payload or content from its cache, which is based on the file system. This is static rendering, meaning rendering at build time. In comparison, we have dynamic rendering, which happens at request time. Let's see this in action. So, back to our users page, let's add a timestamp above the list of users. So, here we add a paragraph and render. First, we create a new date object, and then call toLocaleTimeString. With this, we can see when this page was rendered. Now, back in the browser, let's refresh a few times. So, look, the timestamp is changing. This only happens in development mode. But if we build this application for production, you'll see that the timestamp is not going to change because Next.js will treat this page as a static page. And here's the reason. Earlier, I told you that by default, whenever we use the fetch function, Next.js will cache the data. So, it treats our data as static or unchanging data. So, when rendering this page, Next.js sees that this page has static data, so it decides to render this page statically at build time. But if we disable caching, Next.js thinks the data on this page is going to change, so it's not going to render this page statically, it's going to render it at request time. To see this action, let's go back to the terminal window, stop this process. Now, earlier we used npm run dev to start this application in our development server. Now, to build this for production, we run npm run build. All right, here you can see all the routes that are generated when we build our application for production. So, this is our root route or the home page. We have a route for our favorite icon. We have one for the users page, another for the users/new page, and so on. Now, look at the icon before each of these routes. Here, we only see circles. Now, down here, you can see that a circle means static. So, these pages are automatically rendered as static HTML. Now, if you start this application in production, which we can do by running npm start, and then go back to the browser, let's refresh. Look, the timestamp is not changing because this page was rendered statically at build time. Now, back to this page, let's disable caching and rebuild this application for production. So, as a second argument, we pass an options object, and here we set cache to no-store. Okay? Now, back to the terminal, let's stop this process, and rebuild the application. Lovely. Now, look at the icon before the users route. Instead of a circle, we have a lambda. And down here, you can see that lambda means rendering on the server. So, server-side renders at run time. Now, let's start the application in production. Back to the browser, let's refresh. Now, look, every time you refresh, the timestamp changes. Let's recap everything you have learned about rendering. In Next.js, rendering can happen on the client or on the server. If it happens on the server, it can happen at build time, which is called static rendering, or at request time, which is called dynamic rendering. So, that brings us to the end of this section. In the next section, we'll talk about styling Next.js applications. So, I will see you there. Welcome back to our Next.js course. In this section, we'll explore various ways to style our applications and make them beautiful. We'll cover global styles, CSS modules, Tailwind, and Daisy UI. So, let's jump in and get started. Earlier in the course, we briefly talked about our global style sheet in the app folder. So, let's open up globals.css. In this file, on the top, we have three directives to import the base styles from Tailwind. Now, we're going to talk about Tailwind later in this section, but very briefly, Tailwind is a very popular CSS framework, okay? Then after that, we have this root selector. This is where we typically define custom properties like foreground RGB, and so on. Then we have media prefers-color-scheme: dark. With this CSS feature, which is relatively new, we can detect if the user is in the dark mode or not. If so, you can see that the value of these custom properties is overwritten. Now, down here, you can see that we have used the value of this custom property as the color of the body element. So, we are not using background start and end RGB. They were used earlier when we had a gradient on our home page. So, before going further, let's do a bit of cleanup here. I'm going to delete these two lines, and these two lines from here. And also, let's go back to the terminal and make sure that we're running this application in development, so anytime we make any changes here, we can see the changes immediately. So, npm run dev. Good. Now, back to this file. So, this is our global style sheet, and we should use it for styles that are truly global in our application, styles that apply to all pages, like anything to do with the body element, our headings, our hyperlinks, and so on. Anything that is specific to a page or a component, we should implement it somewhere else. So, one thing you shouldn't do here is you shouldn't define custom classes like user list, because this only applies to a particular component or page. With this approach, as we build more and more components, this global style sheet grows really large and becomes unmanageable. And more importantly, as we change or delete our components, we'll have to remember to come back and do some cleanup here. Otherwise, over time, we'll have a lot of dead styles in this file. If you have been working with CSS for a while, you know what I'm talking about. So, reserve this file for styles that are truly global. For styles that are specific to a page or a component, use CSS modules or Tailwind, which we're going to talk about next. All right, let's talk about CSS modules. A CSS module is a CSS file that is scoped to a page or a component. It's a way to prevent styles from clashing or overriding each other. If you have been working with CSS for a while, you know that if you have the same class defined in two different places in two different style sheets, these classes can override each other depending on how we import these style sheet files. CSS modules aim to solve that problem. Let's see how they work. So, here in the components folder, we have a component called product card. Now, let's say you want to create some styles for this component. So, here we add a new file. We can call this file anything, but it's better to call it the same as the component, so product card. What matters is that the extension has to be dot module.css. Okay? Now, in this file or in this CSS module, we can define classes that are scoped to our product card component. So, let's define a class called card. And of course, we can define this class somewhere else without worrying that these classes would clash, okay? So, here we can apply a padding of 1 rem, and a border of 1 pixel solid CCC. Now, we go back to our component, and import this style sheet. So, we type import styles from current folder, productcard.module.css. The name we assign here doesn't matter, but typically we go with styles, and this will be a JavaScript object. So, the classes that we define in this CSS module will end up being properties of that object. So, here if we type styles, we should see those properties, but I don't know why IntelliSense is not currently working for me, so I apologize for that. So, here we should see the classes we have defined like card, and so on. And that means in CSS modules, we cannot use hyphens when naming these classes, like card container, because this is not a valid name for a JavaScript property. So, in these files, always use the camel case notation. So, we remove the hyphen and make the first letter of the second word uppercase, okay? Now, let's just simplify things. We go with card. Back to our component. So, we have this object. Now, on this div, we set class name to we use our curly braces and set it to styles.card. Now, back to the browser. Here on the home page, you can see the style applied to our card. But, let me show you something interesting. Let's right-click here, and inspect this in Chrome DevTools. Here's our div. Look at the class name. This is not the class that we created, right? This is auto-generated. So, what is happening here is that this project uses a tool called PostCSS for transforming our CSS class names. So, back to our project. Here in the root folder, we have a file called postcss.config.js. In this file, currently we have two plugins. One is Tailwind, the other is autoprefixer. Now, for the most part, we don't have to touch this configuration file, but if you're an advanced PostCSS user, you know this is where you can provide your custom configuration. So, when building our application, Next.js uses PostCSS to transform our class names and generate unique class names that don't clash. This is how CSS modules work. Now, one last thing before we finish this lesson. Currently, I've put the CSS file and the TypeScript file next to each other. If you don't like mixing up your CSS and TSX files, you can group them in folders. So, here we can create a folder like product card. This is a container for our component. In this component, we can have a TSX file and a CSS file, okay? And of course, we can use the same technique with our pages. So, we can use CSS modules to define styles that are local to a particular page. All right, let's talk about Tailwind. So, Tailwind is a very popular CSS framework that uses the concept of utility classes. So, here on tailwindcss.com, you can see that we have a bunch of classes like flex, pt-4, which is short for padding top four, text center, and so on. So, here we have a ton of small utility classes, and we can combine them to style our application. Some people love it, some people hate it. I have to confess that I also have a love-hate relationship with Tailwind, but I think I love it more than I hate it. If you have never used it before, I strongly encourage you to give it a chance, because these days, a lot of projects are built with Tailwind. So, if you want to upgrade your skills and expand your job opportunities, you should have Tailwind in your skill set. So, in Tailwind, we have a ton of small utility classes. For example, for controlling paddings, we have a bunch of classes that start with P, followed by a number, which can be 1 2 3 4, and so on. The larger the number, the more padding we'll have. We also have px for applying horizontal padding. This is the same as applying a left and a right padding. We also have py for vertical padding. We have pt for padding top, pr for padding right, pb for padding bottom, and pl for padding left. Now, you don't have to memorize any of this stuff. As you practice, you'll get the hang of them pretty quickly. Now, for margins, we have similar classes, but they start with M, followed by a number, mx for horizontal margin, my for vertical margin, and so on. Now, for styling text, again, we have a ton of classes. For example, for controlling the size, we have text-xs, which is extra small. We have text small, text base, which is like the regular size. We have text large, x large, 2x large, and so on. For applying colors, we have classes that start with text, followed by a color. So, if you Google Tailwind color palette, on this page, you can see the default color palette that comes with Tailwind. So, we have all these beautiful colors, and for the most part, we don't need to customize them. They just look great as they are, but you can always customize these and use colors that are specific to your brand. Now, look for example for sky, we have various shades of blue that start with 50 and go all the way to 950. The larger the number, the darker the color. You will see an example of this later in this video. Now, back to our slide. For controlling the background color, we have a bunch of classes that start with BG followed by a color code. Now, for controlling the thickness of font, we have a bunch of classes like font thin, font light, normal, medium, bold, and so on. That's the idea of Tailwind. Now, there are a lot more classes in Tailwind that we can cover here, but our focus here in this course is on Next.js and not Tailwind. I just want to show you the basics so you can learn the rest on your own. So, let's see these classes in action and then I will explain why you may want to use Tailwind. So, back to our project. Earlier we used the CSS module to style our product card. Let's see how we can use Tailwind instead of a CSS module to style this component. So, in this file, we don't need to import our CSS module. Instead, we can apply Tailwind utility classes right here. Now, in this lesson, I'm going to use a different set of styles than the styles we applied in our CSS module so you can see more of Tailwind in action. So, we're going to give this some padding which I type P- Now, if you press control and space, you can see all the padding classes. So, we have P-0 which is equivalent to padding zero. We have padding one which is equivalent to 0.25 REM or 4 pixels. And as the number increases, we get more padding. So, this IntelliSense comes with the extension that we installed at the beginning of the course. So, let's give this a padding of five. A vertical margin of five. Now, I want to give it a background color so we type BG- Now, look again in IntelliSense, we can see all the colors. I'm going to go with sky- 400. Now, to make the text white, here we apply text- white. We can make it large. So, here we use text XL or 2XL, 3XL, and so on. Again, on the right side you can see the actual size that is applied. So, for text XL, font size is 1.25 REM or 20 pixels. Now, here's the part that gets interesting. Here we have pseudo selectors like hover and with this, we can apply styles when we hover over this box or this div. So, we can change the background color to BG sky 600 or 500 to make it slightly darker. Now, back to the browser. Here's our div. If you hover over it, you can see the color changes. So, this is how we style our applications with Tailwind. Now, the selling point of Tailwind is that we can style our components right here in our component file. We don't have to juggle back and forth between a CSS file and a component file. Everything is in one place. Now, some people argue that this violates the separation of concerns principle, but I have to disagree with that because the whole idea of separation of concerns is organize our code into distinct sections or modules, each having a separate concern. If you follow this principle, we'll have more opportunities for reuse. But in this case, this React component itself is a module and defines the reuse boundary. So, what we have inside this boundary is purely implementation detail. We can have markup with JavaScript and style all next to each other. What is inside is irrelevant to the outside world as long as this component or this module is reusable. That's just what I think. If you disagree or don't like using Tailwind, that's totally fine. But again, if you want to expand your job opportunities, I highly encourage you to learn Tailwind because it's in high demand these days. But there's one more benefit to using Tailwind and this is the reason I personally love Tailwind. With Tailwind, when we build our application, our final CSS bundle will only have the utility classes that we have used in our markup. So, if tomorrow we delete this div, none of these classes will be in our final CSS bundle unless we have used them somewhere else. So, with Tailwind, we don't have to remember to clean up as we change or delete our components. With CSS modules, if we delete this component, we have to remember to delete the CSS file as well. Or, if we change the structure here, we might still have unused classes in our CSS module. So, we have to remember to come back and clean up. So, that's the selling point that convinced me to start using Tailwind. But on the flip side, I don't like that over time, as our markup gets complex, we'll have a lot of these classes and the code is kind of hard to read, but it's just a matter of getting used to it. It's not terribly bad, but it's something that put some people off early on, but over time, I think the benefits outweigh the downside. All right, and let's talk about DaisyUI. DaisyUI is a very popular component library for Tailwind. It's kind of like Bootstrap for Tailwind. So, if you head over to daisyui.com, you can see all these components. For example, we have accordions, alerts, we have breadcrumbs, buttons, cards, carousel, chat bubbles, and so on. Very, very useful. It's very easy to use, so let's go to the installation page. First, we have to install Daisy as a development dependency. So, I'm going to copy this line. Now, back in VS Code, I've opened my terminal window. You can open it from terminal, new terminal. Now, let's paste that. Good. Next, we should add Daisy as one of the plugins of Tailwind. So, we should go to Tailwind configuration file in the root of our project. So, that is right here. Currently, there are no plugins. So, let's copy this line and paste it here. That's literally all we have to do. Now, let's see how we can use these components. So, as an example, we're going to look at the button component. So, here we have a bunch of classes like BTN, BTN- neutral, BTN-primary, secondary, and so on. Exactly like Bootstrap. Under these classes use Tailwind. So, instead of us manually combining a bunch of small Tailwind classes to create a button, we can just use the button that comes with Daisy. And of course, we can always customize these buttons, okay? So, to create a button, look, we should have an example down here. There you go. This is just a basic button. We also have neutral, primary, secondary, and so on. So, back to our code. Let's style this component that we created earlier. Add to cart. So, here we have a button. We set class name to BTN, BTN-primary. We don't have to import anything in this file, okay? Now, back to the home page. Here's what we get. Let's remove this blue background because it looks kind of odd. So, we're going to go back to product card.tsx and I'm going to remove all these Tailwind classes. Okay? So, here's what we are left with. Now, in Daisy, we have the concept of themes. For example, if you look at this page, themes, you can see all the available themes. Now, in this lesson, I'm going to use a theme called winter. And you can always preview these themes. So, on the top, you can select them and see what your application looks like. Here's the dark mode. Here we have the cupcake theme, and so on. Now, to use a theme, there are two steps we have to follow. First, we have to go in Tailwind configuration file and add this section for DaisyUI. So, here we activate the themes we want to use. So, let's copy this section and go back to tailwind.config.ts. Right after plugins, we paste this. So, we have DaisyUI. We have themes. I don't want to use any of these. I only want to use the winter theme. The second step is to apply this theme on our HTML element. So, back in the documentation, look, here we have a data attribute for specifying the theme. To do that, we have to go to our layout file because this is where we have our HTML element. So, we set data-theme to winter. Now, back to our home page, our button looks blue. Beautiful. Now, let's go to the users page and put these users inside a table. So, let's go to the users page and replace this unordered list with a table. So, we select this and press command and D on Mac or control and D on Windows to activate multiple cursors. Now, we can change these two elements in one go. So, we change it to a table. Then, we press escape to deactivate multiple cursors. Now, inside this table, you want to have a t head. Inside a t head, we want to have a t r, and inside the t r, we want to have two t h elements. Let's press tab. Here's our markup, beautiful. Now, here we want to have two columns. The first one is username, the second is user email. Now, after the t head element, we should add a t body. Then we move mapping over users inside t body and replace l i with t r. So, once again, we press command and d on Mac or control and d on Windows to change both these elements in one go. So, let's change it to t r. Now, inside this t r, we want to have two t h elements. So, t h * 2. Let me put it on a separate line. Good. In the first t h, we want to render user.name. In the second, we want to render user.email. Now, currently, we don't have email in the interface that we defined for our users. That is why we get a compilation error. So, this is another benefit of using TypeScript. The TypeScript compiler tells us about these issues before we run or deploy our application. We can catch these errors at compile time or even while coding. So, up here, we have the user interface. Let's add an email property of type string. Now, the error goes away. Lovely. So, back to the browser. Here's what we get. Now, let's apply a couple of classes from Daisy to make this table look a little bit nicer. So, back to our code. Here's our table. We set class name to table and table- bordered. And of course, you can find these in the documentation for the table component in DaisyUI. Okay, this is much better. Now, I made a mistake earlier. When rendering these rows, I used the t h element. That is why they appear as bold, but we should use t h only as the column of our tables. So, let's change all of these t h elements to t d. Once again, we select one of them and we press command and d to select more of them. So, now we have four cursors. Let's change all of them to t d. Okay, here's what we get. Now, we no longer need the time stamp, so let's remove it from here as well. Good. So, we're done for now. In the next section, we're going to talk about routing and navigation in more detail. Hey guys, I hope you've been having fun watching this tutorial. I just wanted to mention that this tutorial is the first hour of my complete Next.js course. So, after you finish this, if you want to learn more, I highly recommend you to enroll in the full course because it's much faster and easier than jumping between a bunch of random, disconnected tutorials here on YouTube. The full course is 5 hours long and teaches you everything you need to build full stack applications with Next.js. It also comes with a certificate of completion and a 30-day money-back guarantee. So, if you're not happy, ask for a full refund, you get all your money back, no questions asked. In case you're interested, the link is below this video.
Keep this transcript
Save it to LunaNotes and it becomes a real note in your library — editable, searchable, and ready to turn into flashcards or a diagram. Free to start.
Save to LunaNotesOr download subtitles for another video.
These subtitles were extracted using the Free YouTube Subtitle Downloader by LunaNotes.
Related videos
Download Subtitles for FastAPI React B2B SaaS Project Tutorial
Enhance your learning experience by downloading accurate subtitles for the FastAPI + React B2B SaaS full project tutorial. Captions help you follow complex concepts like organizations, users, billing, and roles with ease, ensuring you never miss important details.
Download Subtitles for Learn This Skill to Thrive in 10 Years
Enhance your understanding by downloading subtitles for the video 'Learn This Skill If You Want To Thrive In The Next 10 Years.' Subtitles help you grasp key concepts clearly and make learning accessible anytime, anywhere.
Download Subtitles for Introduction to DaVinci Resolve Full Course
Enhance your learning experience by downloading accurate subtitles for the Introduction to DaVinci Resolve full course. Captions help you follow along effortlessly, improve comprehension, and make the tutorial accessible anytime, anywhere.
Download Subtitles for Beginners Faceless Instagram Theme Page Tutorial
Enhance your learning experience with downloadable subtitles for the comprehensive Beginners Faceless Instagram Theme Page Tutorial. Follow every step clearly in this 5.5+ hour guide, making it easier to grasp key concepts and strategies for 2026. Perfect for non-native speakers and those who prefer reading along.
Download Subtitles for 'How Transistors Run Code' Video
Enhance your understanding of computing with downloadable subtitles for the "How Transistors Run Code" video. Access clear, accurate captions to follow along easily and reinforce your learning experience.
Most viewed
Untertitel für 'Nicos Weg' Deutsch lernen A1 Film herunterladen
Laden Sie die Untertitel für den gesamten Film 'Nicos Weg' herunter, um Ihr Deutschlernen auf A1 Niveau zu unterstützen. Untertitel helfen Ihnen, Wortschatz und Aussprache besser zu verstehen und verbessern das Hörverständnis effektiv.
ดาวน์โหลดซับไตเติ้ล DMD LAND 3 The Final Land Day 1
ดาวน์โหลดซับไตเติ้ลสำหรับวิดีโอ DMD LAND 3 The Final Land Day 1 เพื่อช่วยให้เข้าใจเนื้อหาได้ง่ายขึ้น และเพิ่มความสะดวกในการติดตามทุกช่วงเวลา เหมาะสำหรับผู้ชมที่ต้องการความชัดเจนและเข้าถึงข้อมูลอย่างครบถ้วน
Descarga Subtítulos para NARCISISMO | 6 DE COPAS - Episodio 63
Accede fácilmente a los subtítulos del episodio 63 de '6 DE COPAS', centrado en el narcisismo. Descargar estos subtítulos te ayudará a entender mejor el contenido y mejorar la experiencia de visualización.
Subtítulos para TIPOS DE APEGO | 6 DE COPAS Episodio 56
Descarga los subtítulos para el episodio 56 de la tercera temporada de 6 DE COPAS, centrado en los tipos de apego. Mejora tu comprensión y disfruta del contenido en detalle con nuestros subtítulos precisos y accesibles.
Download Subtitles for Your Favorite Videos Easily
Enhance your video watching experience by downloading accurate subtitles and captions. Enjoy better understanding, accessibility, and language support for all your favorite videos.
Found this transcript useful?
Take it with you. One click puts it in your own LunaNotes library.
Save to LunaNotes