Masaryk University

Styling Your App, Tailwind CSS, Accessibility

Styling is an essential element of any web application, dramatically influencing the user experience. Whether you're building a SaaS product or another basic information system, design is crucial in determining how users perceive and interact with your application. A well-thought-out design can impact user satisfaction and even influence their choice between your service and competitors. Effective styling isn't just about aesthetics; it's also about providing an intuitive user interface. Even if your application has excellent functionality, it is of little use when people cannot work out how to navigate it.

These are common approaches to styling your web application:

Traditional CSS and Sass/Less work on any website. CSS modules and the utility-first approach need a build step, but are otherwise framework-agnostic. CSS-in-JS, component libraries and headless libraries are tied to a JavaScript framework - in our case React. We will go through all of them and then settle on the combination we recommend for this course.

Traditional CSS

CSS logo

Traditional CSS, or Cascading Style Sheets, is the foundational approach to styling web applications. With CSS, developers have the ability to define and control the visual presentation of HTML elements, from fonts and colors to layouts and animations. It offers a level of customization that allows developers to craft unique and tailored user interfaces.

WHY IT'S NOT A GOOD DEVELOPER EXPERIENCE

Although it's mighty, traditional CSS can become unwieldy in larger projects, as maintaining consistency and avoiding conflicts can be challenging. Also, thinking about suitable class names is HARD. There are some standards that developers can follow, for example, BEM.

BEM naming convention for CSS classes

Nonetheless, it continues to be a foundational skill for web developers, and interestingly, all the other styling approaches ultimately rely on traditional CSS, as it is the only language browsers can interpret and render.

Sass/Less

Sass is a dynamic stylesheet preprocessor that introduces powerful features such as variables, nesting, mixins, and functions. It enables more efficient and maintainable CSS code by allowing developers to reuse styles, create modular stylesheets, and apply logic within their stylesheets. Sass files have a .scss or .sass extension, and they must be compiled into standard CSS for web browsers to interpret them correctly.

CSS-in-JS

CSS-in-JS, unlike previous approaches, integrates CSS directly within JavaScript code. With CSS-in-JS libraries like styled components and Emotion, developers can define styles using JavaScript syntax, allowing for dynamic and responsive design. This approach encapsulates styles within components, reducing the risk of conflicts.

const Input = styled.input<{ inputColor?: string }>`
  padding: 0.5em;
  margin: 0.5em;
  color: ${props => props.inputColor || '#B4F474'};
  background: papayawhip;
  border: none;
  border-radius: 3px;
`;

// Render a styled text input with the standard input color,
// and one with a custom input color
render(
  <div>
    <Input defaultValue="QprobabLlyup" type="text" />
    <Input defaultValue="Ggeelen" type="text" inputColor="rebeccapurple" />
  </div>
);
import React from 'react';
import styled from 'styled-components';

const StyledCounter = styled.div`
  /* ... */
`;
const Paragraph = styled.p`
  /* ... */
`;
const Button = styled.button`
  /* ... */
`;

export default class Counter extends React.Component {
  state = { count: 0 };

  increment = () => this.setState({ count: this.state.count + 1 });
  decrement = () => this.setState({ count: this.state.count - 1 });

  render() {
    return (
      <StyledCounter>
        <Paragraph>{this.state.count}</Paragraph>
        <Button onClick={this.increment}>+</Button>
        <Button onClick={this.decrement}>-</Button>
      </StyledCounter>
    );
  }
}

Both examples come from the styled-components documentation, which is why the second one is written as a class component - we do not recommend writing components that way in your projects.

CSS Modules

CSS Modules aims to solve some of the challenges associated with traditional CSS. With CSS Modules, styles are scoped to specific components, preventing global scope pollution and potential style conflicts. Each CSS Module is a standalone file that encapsulates styles for a particular component. Developers can import and use these styles in their JavaScript or TypeScript files, ensuring a tight coupling between styles and components. Additionally, it supports features like local scoping and composition, allowing for creating modular and reusable styles. This approach (should) improve maintainability and reduce the chance of unintended style side effects.

import { useState } from 'react';

import styles from './counter.module.css';

export const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div className={styles.counter}>
      <p className={styles.paragraph}>{count}</p>
      <button className={styles.button} onClick={() => setCount(count + 1)}>
        +
      </button>
      <button className={styles.button} onClick={() => setCount(count - 1)}>
        -
      </button>
    </div>
  );
};

Note the file name. The .module.css suffix is what turns an ordinary stylesheet into a CSS module - it is the signal for the bundler to generate unique class names and hand them to you as an object. Importing plain ./counter.css would apply the styles globally and styles.counter would be undefined.

Component library

A component library in React is a collection of pre-designed and reusable user interface elements (components) that can be easily integrated into your React application. These components are created to maintain consistency in design and functionality across the application, saving development time and ensuring a cohesive user experience. Developers can use these pre-built components to develop user interfaces more efficiently and maintain design consistency throughout their applications, simplifying the development process.

The best known component libraries are Material UI, Ant Design and Chakra UI.

Examples of Material UI components

Advantages of using component libraries

Faster development

If you're satisfied with the majority of what a specific component library offers and require minimal customization, your development speed is likely to increase. You may not need to create any new components, whether small or complex. Depending on your preference, you could receive fully prepared UI components and connect them while adding the necessary functionality.

Don't worry about styling at all

Thanks to its pre-designed and well-tested components, you can largely stop worrying about styling. Libraries follow established design principles and best practices, offering a consistent and visually appealing user interface out of the box. This eliminates the time-consuming and error-prone process of manually crafting styles.

Consistency, Reusability, Efficiency

Using a library brings consistency, reusability, and efficiency to your web development projects. Pre-designed components ensure a consistent and uniform look and feel throughout your application, aligning with established design principles. These components are also highly reusable, reducing the need to recreate similar elements, which saves development time and minimizes code duplication. Furthermore, components come with extensive documentation, simplifying the integration process. In contrast, when creating custom components, you would need to design and document their interfaces, which can be time-consuming.

Disadvantages of using component libraries

Customization

If you're not building your own personal project, where you don't mind your design that much, you can decide to use the pre-designed component library you like the most. At work, you often end up being forced to follow the design that your designer created in Figma. For some projects, it is necessary to follow specific style advice or rules. Then, it may be hard to customize the styling of the pre-designed component library to fit your requirements.

Dependencies, Complexity

Component libraries come with a set of pre-designed components and styles, which can contribute to a larger bundle size. This can impact page load times, especially for users with slower internet connections or on mobile devices. And whatever you do, introducing a component library means shipping code you never use.

You also must manage the library's dependencies, updates, and potential conflicts, which can add complexity to your project's maintenance.

Headless library

A headless React component library is a collection of reusable user interface (UI) components. What sets these libraries apart is that the components are "headless," meaning they are stripped of predefined styles. Instead, they provide the essential logic and functionality while leaving the visual styling entirely to the developer.

Headless React component libraries offer a high degree of flexibility and customization, allowing developers to integrate these components into their projects and apply their styling and design. For styling, developers may use any approach they want.

Accessibility: One of the standout features of Headless libraries is their strong focus on accessibility. It provides accessible building blocks for standard UI components, ensuring that your web application is usable by everyone, including individuals with disabilities. This can save significant time that would otherwise be spent implementing and testing accessibility features.

Examples: HeadlessUI, RadixUI

Utility-First Approach: Tailwind CSS

Rapidly build modern websites without ever leaving your HTML.

Here is a perfect description of utility-first approach

A utility-first CSS framework provides a variety of predefined CSS classes that you can utilize to construct your own components. These classes look like flex mt-2 rounded-full shadow-sm whitespace-nowrap, for example. Many developers consider Tailwind CSS the fastest approach for new applications. The essential advantage lies in eliminating the need to navigate between numerous CSS files, enabling immediate visual feedback as you make changes.

<div class="flex font-sans">
  <div class="relative w-48 flex-none">
    <img
      src="/classic-utility-jacket.jpg"
      alt=""
      class="absolute inset-0 h-full w-full object-cover"
      loading="lazy"
    />
  </div>
  <form class="flex-auto p-6">
    <div class="flex flex-wrap">
      <h1 class="flex-auto text-lg font-semibold text-slate-900">
        Utility Jacket
      </h1>
      <div class="text-lg font-semibold text-slate-500">$110.00</div>
      <div class="mt-2 w-full flex-none text-sm font-medium text-slate-700">
        In stock
      </div>
    </div>
    <div class="mb-6 mt-4 flex items-baseline border-b border-slate-200 pb-6">
      <div class="flex space-x-2 text-sm">
        <label>
          <input
            class="peer sr-only"
            name="size"
            type="radio"
            value="xs"
            checked
          />
          <div
            class="flex h-9 w-9 items-center justify-center rounded-lg text-slate-700 peer-checked:bg-slate-900 peer-checked:font-semibold peer-checked:text-white"
          >
            XS
          </div>
        </label>
        <label>
          <input class="peer sr-only" name="size" type="radio" value="s" />
          <div
            class="flex h-9 w-9 items-center justify-center rounded-lg text-slate-700 peer-checked:bg-slate-900 peer-checked:font-semibold peer-checked:text-white"
          >
            S
          </div>
        </label>
        <label>
          <input class="peer sr-only" name="size" type="radio" value="m" />
          <div
            class="flex h-9 w-9 items-center justify-center rounded-lg text-slate-700 peer-checked:bg-slate-900 peer-checked:font-semibold peer-checked:text-white"
          >
            M
          </div>
        </label>
        <label>
          <input class="peer sr-only" name="size" type="radio" value="l" />
          <div
            class="flex h-9 w-9 items-center justify-center rounded-lg text-slate-700 peer-checked:bg-slate-900 peer-checked:font-semibold peer-checked:text-white"
          >
            L
          </div>
        </label>
        <label>
          <input class="peer sr-only" name="size" type="radio" value="xl" />
          <div
            class="flex h-9 w-9 items-center justify-center rounded-lg text-slate-700 peer-checked:bg-slate-900 peer-checked:font-semibold peer-checked:text-white"
          >
            XL
          </div>
        </label>
      </div>
    </div>
    <div class="mb-6 flex space-x-4 text-sm font-medium">
      <div class="flex flex-auto space-x-4">
        <button
          class="h-10 rounded-md bg-black px-6 font-semibold text-white"
          type="submit"
        >
          Buy now
        </button>
        <button
          class="h-10 rounded-md border border-slate-200 px-6 font-semibold text-slate-900"
          type="button"
        >
          Add to bag
        </button>
      </div>
      <button
        class="flex h-9 w-9 flex-none items-center justify-center rounded-md border border-slate-200 text-slate-300"
        type="button"
        aria-label="Like"
      >
        <svg width="20" height="20" fill="currentColor" aria-hidden="true">
          <path
            fill-rule="evenodd"
            clip-rule="evenodd"
            d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z"
          />
        </svg>
      </button>
    </div>
    <p class="text-sm text-slate-700">
      Free shipping on all continental US orders.
    </p>
  </form>
</div>
card-image

Utility Jacket

$110.00
In stock

Free shipping on all continental US orders.

With the utility-first approach, you have the flexibility to create basically any design you desire without being limited to a single predefined stylesheet. Tailwind has predefined classes for the most fundamental styling elements. However, a prerequisite is a basic understanding of CSS. The advantage is that you don't need to recall the exact CSS syntax.

For instance, if you want to add a subtle shadow to an element, you only need to remember that Tailwind offers the shadow class with different "sizes," such as shadow-xs shadow-sm shadow-md shadow-lg. In contrast, using plain CSS would require you to remember a syntax like box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);

Here's another benefit: Tailwind CSS has established its classes according to industry standards and best practices. Consequently, you won't encounter unconventional values like margin-top: 19.5px. Your task is effectively utilizing these classes while considering the predefined rules for spacing, font sizes, font weights, and other styling elements.

Watch out when reading older articles and older projects: Tailwind v4 renamed the smallest step of several scales. What used to be shadow is now shadow-sm and the old shadow-sm is now shadow-xs; the same shift happened to rounded, blur and drop-shadow. outline-none became outline-hidden, and ring is now 1px in the current color instead of 3px blue.

PERFORMANCE - IT'S TINY ON PRODUCTION

When using Sass or even plain CSS, it's common to accumulate unused CSS classes and encounter duplicated styling over time. Similarly, when working with a component library, it often comes with extensive styling, much of which may be outside of your project. While Tailwind may seem even worse because it provides an insane amount of predefined classes, you never need them all.

During the build, Tailwind scans your source files, identifies the classes you have actually used and generates only those into the final CSS bundle, which reduces the amount of unused CSS to nearly zero.

RESPONSIVE

More than half of users prefer accessing the web via mobile devices. Tailwind CSS simplifies the task of achieving responsiveness compared to other approaches. It offers well-established predefined screen sizes, allowing you to apply different classes based on these screen sizes.

A typical example is arranging elements side by side on desktop screens while stacking them vertically on mobile screens. Achieving this is as straightforward as using <div className="flex flex-col lg:flex-row">{children}</div>.

By default, the flex-direction is set to column, but once the screen size exceeds the lg breakpoint, it switches to row, all while utilizing standard CSS media queries to accomplish this responsive behavior.

HOVER, FOCUS and more

With modifiers like hover:, focus-visible: or disabled: you can achieve even better UX when interacting with all your elements. To see all the possibilities, take a look at Tailwind's documentation.

CONFIGURATION LIVES IN CSS

Since version 4, Tailwind is set up in the stylesheet rather than in a JavaScript config file. A new Next.js project installs tailwindcss together with @tailwindcss/postcss, and the whole framework is pulled in with a single import:

/* src/app/globals.css */

@import 'tailwindcss';

@theme {
  --color-primary: #4338ca;
  --font-display: 'Poppins', sans-serif;
  --breakpoint-3xl: 120rem;
}

Every design token is a CSS variable. Defining --color-primary in @theme is what generates bg-primary, text-primary, border-primary and the rest, and the same variable can be read from plain CSS as var(--color-primary).

A tailwind.config.ts file with a theme.extend object - which you will see in most tutorials and in every project older than 2025 - is the version 3 approach. It still works if you point at it with @config, but for a new project use @theme.

WHY NOT INLINE STYLES?

Comparison of Tailwind utility classes and inline CSS styles

A frequent response to the utility-first approach is questioning whether it's essentially equivalent to inline styles. In certain respects, it resembles inline styles because you're directly applying styles to elements instead of creating a class and styling it separately.

Few important advantages

Consistent design, no magic numbers

Using inline styles, every value is a magic number. With Tailwind CSS you use predefined utilities leading to consistent design. You can still define your own utility class when you need one, and an arbitrary value can be inlined as bg-[#ffffff] - but it stands out as the exception it should be.

Responsive design & hover, focus, and other states

You can't do media queries in inline styles or define different states.

If you want to learn more about differences, see this blog post.

DaisyUI: A Component Library Based on Tailwind CSS

Component libraries based on Tailwind CSS aim to make development even faster. Again, the prerequisite is that you must not be tied to a very specific design. Otherwise, you should avoid a component library and use a headless library with your own styling approach. If you can use one of the provided designs across projects, a Tailwind CSS component library can be a good choice.

These types of libraries do not provide you with pre-built components that you need to import, such as

import { Button } from 'some-library';

DaisyUI specifically provides, similarly to Tailwind, utility classes that you can apply directly to HTML tags.

For example, styling a button to have it look like a DaisyUI button looks like this:

<button className="inline-block cursor-pointer rounded-md bg-indigo-600 px-4 py-3 text-center text-sm font-semibold uppercase text-white transition duration-200 ease-in-out hover:bg-indigo-700 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-indigo-600 focus-visible:ring-offset-2 active:scale-95">
  Tailwind Button
</button>

DaisyUI defines its own utility classes for a button, such as btn btn-primary btn-outline btn-disabled, so the same result takes a handful of classes instead of the wall of them above, and the markup stays readable.

<button className="btn btn-primary">DaisyUI Button</button>

Installation is straightforward. Tailwind has to be installed first, then you add DaisyUI as a dev dependency and register it as a plugin - and since version 5 that happens in your CSS, next to the Tailwind import, not in tailwind.config.js. See the DaisyUI documentation.

@import 'tailwindcss';
@plugin 'daisyui';

Shadcn/ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.

Shadcn UI is a collection of beautifully designed and accessible UI components that developers can easily integrate into their applications. It's built on top of Tailwind CSS and Radix UI and supports various frameworks including Next.js. It is not a component library, but a set of components that you can copy and paste into your application. You don't need to install a package to use these components. You need to copy and paste components that you really need a customize them directly in their source code.

The idea behind this is to give you ownership and control over the code, allowing you to decide how the components are built and styled.

It is the best approach we have tried so far and we recommend it for your projects. When copy pasting components, they are pre-styled, but you can easily change the styling by modifying the Tailwind classes directly in the source code.

Shadcn components were very popular at the beginning of agentic development (for obvious reasons), and they still are. But before long all new websites and apps started to look way too similar. That was the motivation for creating shadcn/create. Shadcn components are built on semantic CSS tokens — background, foreground, primary, border, radius and a handful of others — so overriding those tokens restyles the whole application at once, and dark mode is nothing more than the same tokens redefined under a .dark selector. Tweaking the presets once, before you write your first screen, is the cheapest way to distinguish yourself and to get the consistency we talk about in the next section.

UI, UX and usability

Teaching UI/UX could be a standalone course. We want to motivate you to build systems that look good and are easy to use, therefore we want to at least touch upon some rules which help you to achieve that. We also provide sources for further reading.

It is not about learning one design system (such as Material Design or Glassmorphism) but about general principles. Most of what makes an interface feel "professional" comes down to a handful of decisions you make once and then apply consistently.

Main rules

BE CONSISTENT

Pick a spacing scale, a small set of colors and a couple of font sizes, then stick to them. Tailwind CSS already pushes you in this direction — its predefined scale means you won't end up with margin-top: 19.5px sitting next to margin-top: 22px.

CREATE HIERARCHY

Not everything on the page is equally important. Use size, font weight and color to say what matters. A common beginner mistake is letting every element compete for attention — the result is that nothing stands out at all.

GIVE FEEDBACK

Every action needs a visible reaction: loading states, disabled buttons, error messages, focus rings. The user should never wonder whether their click did anything. This is the very first of Nielsen's usability heuristics, and it is the one most often ignored.

USE FEWER THINGS

One accent color, one font family, one border radius. Constraints make a design look intentional. If you need a palette, generate one at coolors.co and preview it on a real layout with Realtime Colors; for typography, Google Fonts is more than enough. Accessibility is a part of usability too — we cover it in the next section.

CONVENTIONS HAVE A SHELF LIFE

Conventions are not laws. Recent example: The CSS specification has always defined pointer as the cursor that "indicates a link", and browsers have always given a plain <button> an arrow — yet for two decades the web taught everyone that a hand means "clickable". Tailwind CSS v4 sided with the specification and stopped putting cursor: pointer on buttons, and the argument has not stopped since; plenty of projects paste the old behavior straight back. Both sides have a point, which is exactly why it is worth knowing about: a flat button, unlike the chunky OS buttons the rule was written for, has little else left to signal that it can be pressed. When a convention shifts, find out which problem it was solving before you decide to follow it — or to ignore it.

Worth your time: Nielsen Norman Group's 10 usability heuristics — the short list every designer knows — and visual design rules you can safely follow every time, which is as concrete as design advice gets. If you want to go deeper, Refactoring UI have great examples, and Laws of UX collects the psychology behind these rules.

Agentic development

AI agents are good at producing UI that looks finished and bad at producing UI that behaves well — they optimize for a screenshot, and a screenshot does not show what happens when you press Tab, when the list comes back empty, or when the request takes four seconds. The defects are the ones you don't see while looking at the page: a removed focus ring, a clickable div where a button belongs, a form that blocks paste, content that jumps once the data arrives.

The fix is an explicit checklist instead of taste. Vercel's Web Interface Guidelines are a good starting point — keep rules like these in your repository so every prompt starts from them, and review the result by keyboard, not just by eye.

Accessibility

Accessibility is an important part of web development that is often glossed over. It would help if you thought about it from the start for many good reasons.

  1. Inclusivity: Accessibility ensures that everyone, regardless of disabilities, can use your app.
  2. Better User Experience: Accessibility features improve overall user satisfaction.
  3. SEO Benefits: Accessible websites tend to rank better on search engines.
  4. Future-Proofing: Building accessibility from the start saves time and resources.
  5. Legal Compliance: When working on public-facing sites like government websites, accessibility features may even be required by law.

Thankfully, modern HTML has many accessibility features built right into the elements websites are built from that browsers and accessibility tools understand and can work with.

Semantic elements

While you can build your whole website out of div elements that are styled and hooked up with JS to do whatever you need, this approach is far from optimal. It's better to use correct HTML tags for the purposes they were made for. Let's take this awful HTML snippet as an example:

<span style="font-size: 3em">My heading</span> <br /><br />
This is the first section of my document.
<br /><br />
I'll add another paragraph here too.
<br /><br />
1. Here is
<br /><br />
2. a list for
<br /><br />
3. you to read
<br /><br />
<span style="font-size: 2.5em">My subheading</span>
<br /><br />
This is the first subsection of my document. I'd love people to be able to find
this content!
<br /><br />
<span style="font-size: 2.5em">My 2nd subheading</span>
<br /><br />
This is the second subsection of my content, which I think is more interesting
than the last one.

While this page may look fine when you look at it in your browser, any visually impaired user would need help trying to understand the information contained within. Another place where this snippet would perform poorly is SEO since search engines wouldn't know how to parse and index this content. Now compare it to semantically correct markup:

<h1>My heading</h1>

<p>This is the first section of my document.</p>

<p>I'll add another paragraph here too.</p>

<ol>
  <li>Here is</li>
  <li>a list for</li>
  <li>you to read</li>
</ol>

<h2>My subheading</h2>

<p>
  This is the first subsection of my document. I'd love people to be able to
  find this content!
</p>

<h2>My 2nd subheading</h2>

<p>
  This is the second subsection of my content, which I think is more interesting
  than the last one.
</p>

You can clearly see the title of this page; you can also see it has two sub-sections, an ordered list with three items, and some paragraphs. This is the most fundamental difference between correct and incorrect usage of HTML elements.

Most important elements

<header>, <main> and <footer>

These three tags define the top-level structure of your website. The header usually contains a common website name, general navigation, or logged-in user info. Not all sites require a footer, but you should expect to find contact info, terms and conditions links, business opening hours, or other helpful links. The main tag then wraps the actual content of the given page you are currently on.

Semantic HTML elements in a typical page layout

A good practice is also to add a Skip to Content link that allows keyboard users to skip over header navigation directly into the main section of your page.

<h1>, <h2>, <h3>

Heading tags are most valuable for a proper SEO of your page. There should always be only one h1 tag, followed by h2 tags, which can also have h3 tags. You shouldn't skip from h1 directly to h3. Lower heading tags should also be used sparingly since overly structuring your content may make it harder to follow.

<nav>

Navigation should contain a list of links used to navigate your website. Usually, the main navigation is inside the header, but you can also have other nav elements that handle navigation within separate subparts of your website. You can use ul and li elements to semantically structure the links as a list for screen readers that you can then style any way you want for general users.

<button> and <a>

While you can style any element to look like a button and add JavaScript event handlers, screen readers will not recognise it as something you can interact with. That's why you should always prefer a button element for the interactive parts of your website and an a tag for any links that trigger navigation.

Role attribute

The elements above work out of the box because each of them already carries an implicit role - a <button> is announced as a button without anyone writing role="button". Those implicit roles cover most common cases, but there are many more roles an element can have: inputs come with roles such as radio or combobox, and for a custom widget you may need a more specific role like tab or menu instead of the generic button. Setting a role by hand only makes sense when no HTML element expresses what you are building - and it changes nothing about the behaviour, only what assistive technology announces.

WAI-ARIA

The role attribute is a part of the Accessible Rich Internet Applications (ARIA) set of rules that help make the web more accessible. ARIA also defines how to use attributes other than the role that can describe the current state of various interactive elements such as dialogs or draggable elements. This is why often using existing UI libraries is advantageous because they should have all these accessibility features covered.

Before you submit, walk through the A11Y Project checklist — it turns WCAG into something you can actually tick off — and verify your colors in the WebAIM contrast checker. For building accessible components yourself, Inclusive Components by Heydon Pickering works through the common patterns one by one.

Next lecture

In the next lesson, we'll look at the interactivity of a React application. We will explain hooks, lifecycle and component state. We will discuss the basic rules to follow when working with state.

Assignment

This week, style a responsive page using Tailwind CSS to display a GitHub repository description. The layout should include fixed top navigation, sidebars, and main content. Ensure responsiveness and basic accessibility.