Ultimate CSS guide: Build 3 card components.
Tags: beginners, webdev, tutorial, css
Published: 2022-12-07 16:25:56

- [Introduction](#introduction)
- [Final Result](#final-result)
  * [QR Card](#qr-card)
  * [Product Review](#product-review)
  * [Rating Card](#rating-card)
- [QR code component](#qr-code-component)
  * [padding vs margin](#padding-vs-margin)
  * [Box-sizing](#box-sizing)
  * [Reset body padding and margin](#reset-body-padding-and-margin)
  * [variables](#variables)
    + [Syntax](#syntax)
    + [Using variables](#using-variables)
- [Variables for QR card](#variables-for-qr-card)
- [Container](#container)
  * [container styles](#container-styles)
    + [flex-box](#flex-box)
    + [center the elements](#center-the-elements)
    + [em and rem](#em-and-rem)
- [QR card](#qr-card)
  * [max-width and min-width](#max-width-and-min-width)
  * [QR card styling](#qr-card-styling)
    + [Image Styling](#image-styling)
    + [Section and Paragraph](#section-and-paragraph)
    + [Font Family](#font-family)
      - [Using the font](#using-the-font)
- [Product Review Card](#product-review-card)
  * [Familiar Code.](#familiar-code)
    + [HTML](#html)
      - [Fonts](#fonts)
    + [CSS](#css)
  * [New Concepts](#new-concepts)
    + [semantic HTML](#semantic-html)
    + [unsemantic HTML](#unsemantic-html)
    + [rest of the HTML](#rest-of-the-html)
    + [Styling](#styling)
    + [Product details](#product-details)
    + [buttons](#buttons)
  * [Desktop Design](#desktop-design)
  * [Rating Card](#rating-card-1)
    + [HTML](#html-1)
    + [Basic common styles](#basic-common-styles)
    + [Card](#card)
    + [Thank you card](#thank-you-card)
    + [Utilities](#utilities)
    + [JavaScript](#javascript)
      - [Event bubbling](#event-bubbling)
- [Conclusion](#conclusion)

# Introduction

As powerful as CSS is as complex, learning CSS can be challenging, but I aim to make it easy with project-based learning, with this and subsequent tutorials. We are going to build three card components in order of complexity, and will explain everything as we go along.

You can find the complete code on [git](https://github.com/SfundoMhlungu/css-tutorials/tree/main/css-newbie); if you want the starter files only, you can download them on frontend mentor:

[Product preview](https://www.frontendmentor.io/challenges/product-preview-card-component-GO7UmttRfa)

[QR Component](https://www.frontendmentor.io/challenges/qr-code-component-iux_sIO_H)

[Interactive Rating Component](https://www.frontendmentor.io/challenges/interactive-rating-component-koxpeBUmI)


# Final Result

## QR Card


![QR Card](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5veyhu422g5a60m833ls.png)

## Product Review


![Product review](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xg5c4m1xx5vusvyvuhzu.png)

## Rating Card


![Rating Card](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6f6sn1036hhvfxni741d.gif)

# QR code component

Project setup:

Extract the files from frontend mentor and copy the image folder and index.html to your created folder.

Create and link style.css file in your HTML.

A split setup in vs code is ideal for this tutorial, and I place the style guide and design on the right and the code on the left.


![Vs code setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/md1zsa7t9ybd1d5lrrg8.PNG)

you can split your vscode by right-clicking on a file and click 
the open to the side option.

if you see`...` in the code, it means continuation from the previous code.

Lastly, I follow mobile-driven development. For every project, we start with the mobile design file first.

## padding vs margin

Padding is the space between the element's border and the content inside, while margin is the space around the element's border.


![margin vs padding](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bu1587vg9py6ok4fw8yr.jpeg)

## Box-sizing

CSS property to set how the total width and height of an element is calculated.

```css
*{
  box-sizing: border-box;
}
```

border-box accounts for padding and margin as part of the element size, a 100px sized element with a border-box includes the margin and padding in it, w/o border-box padding, and the margin are added on top of the size, the element will look bigger than expected.

## Reset body padding and margin

Some HTML elements have margin and padding by default, and you reset by making both or either 0.

```css
body {
  padding: 0;
  margin: 0;
}
```

In this case, we do not need space around the body element.

## variables

a custom CSS property that allows the reuse of values.

instead of typing the same color over and over again, we can use a variable,

### Syntax

```css
 --myvar : property;
```

```css
:{
 
  --lg-fontsize: 34px;
  --primary-color: blue;
}
```

they start with --, you can camelcase: `--lgFontsize`, separate: `--lg-fontsize` as long as your variable starts with --.

### Using variables

```css
.myClass { 
 font-size: var(--lg-fontsize); 
 color: var(--primary-color)

}
```

# Variables for QR card

`:root{}` - root selector, select the root of the document, &lt;html&gt;

```css
:root{
     --light-gray:hsl(212, 45%, 89%);
    --grayish-blue:hsl(220, 15%, 55%); 
    --dark-blue: hsl(218, 44%, 22%);
   
}
```

# Container

The QR card is centered in a dark container that takes the entire screen(viewport).

VH and VW CSS units are relative to the visible screen size or viewport, for example:

```css
.Vexample{
   width: 100vw;
   height: 100vh;
}
```

100 vh - the elements take 100% of the viewport height-wise, while 200 takes twice as much, 50 half, and so forth, all relative to the screen.

`vw` - view width.

`vh` - view height

## container styles

```xml
  <div class="container">
       <!-- QR card here -->
 </div>
```

```css
.container{
    height: 100vh;
    background-color: var(--cream);
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1em;
   

}
```

we only set the height, the div already takes the entire width

```css
  height: 100vh;
```

### flex-box

```css
  display: flex;
```

is a web layout model, it is one dimensional. You can either place elements as a row or column, flex-box is responsive, a deep dive on web layouts require its own article if you need a refresher or intro [MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS\_layout/Flexbox) has excellent articles.

### center the elements

flex-box allows us to position elements with `justify-content` and `align-items`

Justify - positions the elements inside the container horizontally,

based on a given instruction e.g:

`flex-start` - being the start of the container horizontally

`center` - center of the container

`flex-end` - end of the container

and many more ways: `justify-evenly, space-between`.

Align - positions the elements inside the container vertically.

flex will center everything vertically and horizontally with the following.

```css
 justify-content: center;
 align-items: center;
```

### em and rem

em is a CSS unit relative to the font size of the parent element, while rem is relative to the font size of the root element.

the default font size for browsers is 16px. Therefore, `1rem or em` is 16px unless you override the font size from the root or parent container.

formula: `em or rem * font size = unit`

therefore: `1em * 16px = 16px`

The space between the container and content all around will be 16px

```css
 padding: 1em;
```

you can set a specific side or sides etc

```css
   padding-left: ;
   padding-bottom: ;
   padding-top: ;
   padding-right: ;
```

# QR card

## max-width and min-width

max suffixed with width or height prevents an element from becoming larger than the value specified, min does the opposite and prevents the element from becoming smaller than the value specified.

```xml
  <div class="container">
         <div class="QR_card">
                <img src="./images/image-qr-code.png">

          <section>
            <h1>Improve your frontend skills by building projects</h1>
    
            <p>Scan the QR code to vist Frontend Mentor and take your coding skills to the next level</p>
          </section>
        </div>
 </div>
```

## QR card styling

```css
.QR_card{
    background-color: white;
    max-width: 375px;
    margin: 2em;
    height: max-content;
    border-radius: var(--radius);

}
```

add radius as variable(for rounded corners)

```css
:root{
...
 --radius: 1.5em;
}
```

The QR card will never grow beyond `375px` mobile size value from the style guide.

```css
 max-width: 375px;
```

height of the card will be controlled by the size of the content inside.

```css
 height: max-content;
```

border-radius is for rounded corners.

```css
 border-radius: var(--radius);
```

### Image Styling

Styling images with CSS can be pretty tricky, the following is basic, and we will build upon it.

```css
.QR_card img {
    height: 40%;
    width: 100%;
    padding: 1em;
    border-radius: var(--radius);
}
```

The styles are self-explanatory; however, you typically don't want to round edges on an image, but the container, we will explore this later.

### Section and Paragraph

```css
.QR_card section{
    text-align: center;
    padding: 1.5em;
}

.QR_card p {
    font-size: 15px;
}
```

### Font Family

The style guide specifies Outfit for font, weight being `300 and 700` you can follow this [link](https://fonts.google.com/specimen/Outfit) to download the font on google fonts; if you already know how to do that, you can link the font with HTML below, in the head tag.

```xml
<head>
  ...

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;700&display=swap" rel="stylesheet">

 <link rel="stylesheet" href="style.css">
</head>
```

#### Using the font

```css
body {
   ...
  font-family: "Outfit"; 
}
```

all elements inside the body tag will use Outfit font as the default font,

lastly, we need to update font weights, larger font weights are for headers etc, while smaller ones are for paragraphs and the like.

```css
h1 {
    font-weight: 700;
}

p{
    font-weight: 400;
    color: var(--grayish-blue)
}
```

the color property set's the color of the text, gray or grayish colors work well with text, that's why I picked grayish-blue.

The QR card component is complete; all subsequent projects and articles will build from the basics learned here, `I will only explain new concepts`.

# Product Review Card

The setup is the same as QR card, extract the relevant files to a new folder, create and link `style.css`.

## Familiar Code.

### HTML

#### Fonts

```xml
<head>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

 <!-- Fraunches && Montserrat  -->
 <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,700&family=Montserrat:wght@500;700&display=swap" rel="stylesheet">
<!-- Custom Styles  -->
 <link rel="stylesheet" href="style.css">
</head>

<body>


  <div class="container">
  
    <div class="product_card">

    </div>
  </div>
</body>
```

### CSS

```css
* {
    box-sizing: border-box;
        
   

}

:root{
    --dark-cyan: hsl(158, 36%, 37%);
    --dark-cyan-darker:hsl(158, 36%, 17%);
    --cream: hsl(30, 38%, 92%);


    --very-dark-blue: hsl(212, 21%, 14%);
    --dark-grayish-blue: hsl(228, 12%, 48%);
    --white:  hsl(0, 0%, 100%);
}

body{
    margin: 0;
    padding: 0;
  

    font-family: "Montserrat";
    font-weight: 500;


}

.container{
    height: 100vh;
    background-color: var(--cream);
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1em;
   
}
```

## New Concepts

### semantic HTML

HTML elements that clearly describe their role to both the browser and developers, [MDN article](https://developer.mozilla.org/en-US/docs/Glossary/Semantics) for more.

example: the following is semantic(meaningful), by reading the HTML you know what's going on and can follow the structure,

```xml
    <div>
       <section>
          <h1></h1>
          <p></p>
       </section>

       <section>
          <h2></h2>
          <p></p>
       </section>
       <form>
          
       </form>

    </div>
```

### unsemantic HTML

```xml
  <div>
       <div>
          <span></span>
          <span></span>
       </div>

       <div>
          <span></span>
          <span></span>
       </div>
       <div>
          
       </div>

    </div>
```

Writing semantic HTML is vital for a whole lot other reasons than code readability and is important when your projects get larger. writing semantic HTML takes practice and familiarity with many HTML elements. This is a newbie tutorial I will use as little as possible and limit it to a few elements to avoid information overload.

### rest of the HTML

```xml
  <div class="product_card">
     <section class="product_img">
        <img src="./images/image-product-mobile.jpg" class="hidden-for-desktop"/>

        <img src="./images/image-product-desktop.jpg" class="show-for-desktop hidden-for-mobile"/>

      </section>

      <section class="product_details">
      
       <small>perfume</small>
       <h2>Gabrielle Essence Eau De Parfum</h2> 
      
       <p>
          A floral, solar and voluptuous interpretation composed by Olivier Polge, 
          Perfumer-Creator for the House of CHANEL.
       </p>
    
      
       <h1>$149.99 <span>$169.99</span></h1>
        
        
      <div>
        <a href="#" class="btn">
          <img src="./images/icon-cart.svg"/>
          Add to Cart
        </a>
      </div>
       
      
      </section>
  </div>
```

### Styling

```css
.product_card{
    max-width: 375px;
    height: fit-content;
    background-color: var(--white);
    border-radius: 1.2em;
    overflow: hidden;  
}

.product_img {
    height: 10em;
   
}
```

anything inside `.product_card` that overflows or <mark>is bigger than 375px</mark> will be hidden

```css
overflow: hidden;
```

If you comment out overflow hidden, you will notice the image overflows, the card is smaller than the image. remember what I said about images and them being unwieldy, it is overflowing outside its parent `.product_img`. let's fix that by directly targeting the image,

```css
.product_img img{
   
    width: 100%;
    height: 100%;
  
    object-fit:cover;
    object-position: center;

}
```

setting the width and height works perfectly fine, but object-fit and position make sure the image looks good responsively(as screen size changes). <mark>it will cover the container, and the zoom or crop will be at the center of the image</mark>.

The mobile design is taking shape.

### Product details

```css
.product_details{
    padding: 1em;
}

.product_details h2 {
    font-family: "Fraunces";
    font-weight: 700;
    margin: .3em 0;
    color: var(--very-dark-blue)
}
```

the following is a short hand for manipulating multiple sides at once, works for both margin and padding

```css
   margin: .3em 0;
```

translation: `margin: top and bottom = .3em left and right = 0`

```css
.product_details small {
    text-transform: uppercase;
    font-weight: 700;
    color: var(--dark-grayish-blue);
    letter-spacing: .3em;
}

.product_details p {
   
    font-size:14px;
    color: var(--dark-grayish-blue);
}
```

There's nothing that is new or special with the above CSS, except maybe `letter-spacing`, which is the space between letters.

```css
.product_details h1 {
    display: flex;
    color: var(--dark-cyan);
    font-family: "Fraunces";
}
```

`display: flex;` for a one-dimensional layout, h1, and span must be in a single row.

```css
.product_details h1 span {
    display: flex;
    align-items: center;
    padding-left: .8em;
    text-decoration-line: line-through;
    font-size: .4em;
    color: var(--dark-grayish-blue);
    font-family: "Montserrat";

}
```

`text-decoration-line: line-through;` - strike thru the text.

### buttons

Depending on your love or hate relationship with CSS, styling buttons can be either the most annoying or fulfilling task, the following styles are the basis for most button styles. Keep them somewhere accessible for reuse, it does not even matter that much if you don't understand how they entirely work, as long as you know which part to customize for a custom button.

```css

.btn {


    display: inline-block;
    /* outline: 0; */
    /* appearance: none; */
    padding: 12px 12px;
    margin-bottom: .5em;
    border: 0px solid transparent;
    border-radius: 4px;
    text-decoration: none;
    cursor: pointer;
    background-color: var(--dark-cyan);
    /* box-shadow: rgb(19 170 82 / 40%) 0px 2px 3px; */
    color: rgb(255, 255, 255);
    /* font-size: 14px; */
    font-weight: 400;
    width: 100%;

    transition: all 150ms ease-in-out 0s;
  

}

.btn {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 5px;

}

.btn:hover{
    background-color: var(--dark-cyan-darker);
}
```

Important for customization.

```css
 background-color: var(--dark-cyan);
   /* text color */
 color: rgb(255, 255, 255);
    /* affect the size of the button */
 padding: 12px 12px;
 margin-bottom: .5em;

  /* roundedness */
 border-radius: 4px;
  /* remove a tag underline*/
 text-decoration: none;

 /* button feedback on user interaction*/
.btn:hover{
    background-color: var(--dark-cyan-darker);
}
```

The card should be looking pretty good on mobile,

## Desktop Design

Responsive development can be complex at times, accounting for multiple screen sizes, devices, and modes can be complicated, It helps to have at least one simple robust approach to responsive development to get up and running quickly. That's the method I am going to teach you.

Simplifying everything to a single break-point reduces the complexity significantly, the idea is to have a point where everything below is considered mobile, and anything above is desktop; this way you don't have to worry about a plethora of devices; 1024px is the magical breakpoint.

```css
.hidden-for-mobile {
    display: none;
}

.show-for-mobile {
    display: block;
}

@media screen and (min-width:1024px){
/*styles inside this block will only apply to screens from 1024px upwards*/
.hidden-for-desktop{
        display: none;
        
    }

    .show-for-desktop {
        display: block;
    }
}
```

Currently, the card is a one-dimensional column, everything is stacked, we want it to be a one-dimensional row on desktops, and we know from previous experience we can achieve that with flexbox.

Override the layout of `.product_card with a display :flex;`

```css
@media screen and (min-width:1024px){
...
display: flex;
/*allowing the card to take more width*/
max-width: 600px;
}
```

Image and details must be the same width and take the entire height and width of its parent.

```css
@media screen and (min-width:1024px){
  ...
   .product_card > * {
        width: 50%;
    }

    .product_img {
        height: 100%;
    }
}
```

.product\_card &gt; \* selects all the children of the product card and applies the width of 50% to each child. finally, fix the details to be a column.

```css


@media screen and (min-width:1024px){
...

   .product_details {
        display: flex;
        flex-direction: column;
        justify-content: center;
    }

 

    .product_details h2 {
      font-size: 2.3em;
    }
}
```

if you approach responsive development with this basic mentality and approach until you are comfortable, it's hard to go wrong, I've built multiple projects quickly with this approach, you can trust it is well-tested.

## Rating Card

The focus here is not the styles or design, but I am introducing a bit of JavaScript and style manipulation based on a specific state. The styles are actually almost the same as the QR card. I will not explain them that would be tedious and repetitive, the focus is JavaScript.

### HTML

![](./images/icon-star.svg align="left")

```xml
  <h2>How did we do?</h2>

  <p>
    Please let us know how we did with your support request. All feedback is appreciated 
    to help us improve our offering!
  </p>
 

  <section class="rating">
    <span class="icon rate">1</span> 
    <span class="icon rate">2</span> 
    <span class="icon rate">3</span> 
    <span class="icon rate">4</span> 
    <span class="icon rate">5</span> 

  </section>


  <div>
    <a href="#" class="btn">
   
     Submit
    </a>
  </div>

</div>
 
<!-- thank you card -->
<div class="card hidden" id="thanks">
  <div class="hero_img">
    
    <img src="./images/illustration-thank-you.svg"/>
    <span> You selected <label id="rate">5</label>  out of 5</span>
  </div>
 
 <div class="details">
  
  <h2>Thank you!</h2>

  <p>
    We appreciate you taking the time to give a rating. If you ever need more support, 
    don’t hesitate to get in touch!
  </p>
 
 </div>

</div>
```

### Basic common styles

```css
*{
    box-sizing: border-box;
}

:root{
    --orange:  hsl(25, 97%, 53%);
    --white: hsl(0, 0%, 100%);
    --light-grey: hsl(217, 12%, 63%);
    --medium-grey: hsl(216, 12%, 54%);
    --dark-blue: hsl(213, 19%, 18%);
    --dark-blue-lighter: hsl(213, 19%, 22%);
    --very-darkblue: hsl(216, 12%, 8%);
}

body{
    margin: 0; 
    padding: 0;
}

.container{
    display: flex; 
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: var(--very-darkblue);
    padding: 1em;
}
```

### Card

```css

.card {
  display: flex;
  flex-direction: column;
  background-color: var(--dark-blue);
  border-radius: 1.2em;
  max-width: 375px;
  height: fit-content;
  padding: 2em;
  color: var(--white);
}

p {
    color: var(--medium-grey);
    margin-bottom: 0;
}
.icon {
    background-color: var(--dark-blue-lighter);
      /*  circle start */
    border-radius: 50%;
    width: 48px;
    height: 48px;
    /* circle end */px
    width: max-content;
    padding: .7em;
}

.icon img {
    width: 28px;
    height: 28px;
    /* padding: 2em; */
    
}


.rating{
    display: flex;
    /* justify-content: space-evenly; */
    padding: 1.5em 0;
    
}

.rate {
    padding: 1em;
    margin-right:1.5em;
    cursor: pointer;
}

.rate:hover{
    background-color: var(--light-grey);
}

.selected {
    background-color: var(--orange);
}
```

### Thank you card

```css
.hero_img{
    display: grid;
    place-content: center;
    gap: 1em;
    padding-bottom: 1em;

}
.details{
    text-align: center;
}
```

### Utilities

```css
.btn {


    display: inline-block;
    /* outline: 0; */
    /* appearance: none; */
    padding: 15px 12px;
    margin-bottom: .5em;
    border: 0px solid transparent;
    border-radius: 20px;
    text-decoration: none;
    cursor: pointer;
    background-color: var(--orange);
    color: rgb(255, 255, 255);
    font-weight: 400;
    width: 100%;

    transition: all 150ms ease-in-out 0s;
  

}

.btn {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 5px;
   text-transform: uppercase;
   
}

.btn:hover{
    background-color: var(--white);
    color: var(--orange);
}

.hidden{
    display: none;
}
```

### JavaScript

If you are comfortable with JS, you can copy the code and explore it on your own; else read on as I explain and add a script tag at the end of the body tag.

```javascript
  <script>
    let rating = 0;
    document.querySelector(".rating").addEventListener("click", (e)=> {
      const allRatings = [1, 2, 3, 4, 5]
    
      if(allRatings.includes(+e.target.outerText)){
         
        const childs = document.querySelector(".rating").children
        for(let i = 0; i < childs.length; i++){
         childs.item(i).classList.remove("selected")
        }
        rating = e.target.outerText
        e.target.classList.add("selected")
      }
    })

    document.querySelector(".btn").addEventListener("click", ()=> {

       if(rating === 0) return; 
      document.querySelector("#rating_card").classList.add("hidden")
      document.querySelector("#rate").innerHTML = rating
      document.querySelector("#thanks").classList.remove("hidden")
    })
  </script>
```

#### Event bubbling

Events fired from children of an element can bubble and be caught at the parent level; the idea is instead of adding event listeners to a bunch of children and handling them individually, we can add a single event listener to the parent, which will account for all the children when clicked,

instead of adding an event for each rating, we add one to the parent element; when a rating is clicked, the event will bubble.

```javascript
 
document.querySelector(".rating").addEventListener("click", (e)=> {
}
```

this means anything inside `.rating`, even if it's not the ratings themselves; if clicked, will send an event, so we need a way to tell if the bubbled event is from one of the ratings. the event object e has a target property that represents the element clicked, we can query it and see if it's one of the ratings

```javascript
document.querySelector(".rating").addEventListener("click", (e)=> {
    const allRatings = [1, 2, 3, 4, 5]
    if(allRatings.includes(+e.target.outerText)){
    
    }

}
```

e.target.outerText is the visible text in your browser, text inside the tags 1  in this case. +e.target.outerText - the plus is another way in JS to parse a string to a number, because we are comparing with the allRatings array, which contains numbers. the following code says if the element clicked has an outer text of either 1, 2, 3,4,5 we care about that element, run the if block, else do nothing.

```javascript
  if(allRatings.includes(+e.target.outerText)){
         
        const childs = document.querySelector(".rating").children
        for(let i = 0; i < childs.length; i++){
         childs.item(i).classList.remove("selected")
        }
        rating = e.target.outerText
        e.target.classList.add("selected")
      }
```

when a rating is selected, we need to make sure that any rating that was selected before we remove it as selected; this will happen when the user changes their mind after selecting a rating.

```javascript
 const childs = document.querySelector(".rating").children
 for(let i = 0; i < childs.length; i++){
      childs.item(i).classList.remove("selected")
    }
```

we are getting all the children of the .rating element and removing the selected class from them if any has it.

```javascript
childs.item(i).classList.remove("selected")
```

the selected class

```css
.selected {
    background-color: var(--orange);
}
```

after removing any selected from a previous selection, we mark the new element as selected

```javascript
// for display in the thank you card
rating = e.target.outerText e.target.classList.add("selected")
```

all that is left is to handle the submit button, on submit we want to transition from the rating card to the thank you, we follow the same process of adding and removing classes with classList and the elements will be updated accordingly.

```javascript
    document.querySelector(".btn").addEventListener("click", ()=> {
      // if no rating is selected we don't want to run the code below we return.
       if(rating === 0) return; 
    // hiding the rating card
      document.querySelector("#rating_card").classList.add("hidden")
      // setting the  rate for the thank you card 
      document.querySelector("#rate").innerHTML = rating
     // showing the thank you
      document.querySelector("#thanks").classList.remove("hidden")
    })
```

as a challenge, you can implement the back button for the user to go back and change their rating, while seeing their old rating; that could be a  great challenge.

# Conclusion 

This article is the beginning of multiple  HTML, CSS, JavaScript, React, and Svelte articles, as I am taking this blog to that new direction of project-based learning.
In the meantime, if you want to take your HTML, CSS, and JavaScript skills from beginner to writing large applications in a focused path, I have a dedicated digital download with [1v1 help](https://www.buymeacoffee.com/mhlunguskF/e/104259), [w/o 1v1 help](https://www.buymeacoffee.com/mhlunguskF/e/104258)
 
If you like the blog and like to support you can buy me a coffee, your support would be highly appreciated.

[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/default-black.png)](https://www.buymeacoffee.com/mhlunguskF)

Thank you for reading.