How to use Styled Components to Customize Your Blog.
Tags: nextjs, css, styledcomponents, design
Published: 2022-07-22 23:37:00

_This is lesson 7 in a tutorial on how to create a blog using NextJS, Sanity, and Vercel.
 If you are just here for help with Styled Components then you will need to implement your own text for the elements or follow my guide from lesson 1._
- _I also have a link to a working sandbox of this code in my [Preview](#preview) section that includes text data you can use instead._
- _I didn't implement responsiveness for small screens. I set up the entire post information in a grid so implementing it won't be difficult. I'm leaving it up to you to create your own unique mobile view!_

> I've done some tweaking to the props we fetch. I will explain that part after the Planning, so if you just want Styled Components, you can skip ahead. 
> You should also create additional posts (at least have 2 in total) to see our `Recent Posts` sidebar.

<hr />

## Planning

It is never a good idea to style from your code. What I mean is, you should have an idea ahead of time on how you want things to look (even sketch it out), then replicate that with your code.

On the topic of 'sketching it out', I did just that. In only a couple of minutes I was able to create this [Figma design.](https://www.figma.com/file/2zH6kSFuDUlBzOgBT4s29b/Untitled?node-id=0%3A1)
> You might need to signup to view it if you don't have a Figma account, but it's worth it to have one. The amount of time you save by sketching things out cannot be understated.

I didn't make the most complex UI ever, but it's perfectly fine for our needs.  You can also click each element and see it's name (purpose) on the left hand side of the screen under `Layers > Desktop-1`.

One of the elements is called `Social Media Buttons`, so we are going to go ahead and install an npm package that is standard for almost every project.

In the command line of your project, run 
```
npm i react-icons --save &&
npm i react-portable-text
```

Reading the [React Icons docs](https://react-icons.github.io/react-icons/) will explain how to use it and let you search for any icon you want. All we have to do is find the code for the icon we want, import it, and insert it like a React component.

[React Portable Text](https://www.npmjs.com/package/react-portable-text) is what we are going to use to display the `body` value we couldn't use in the last lesson.

<hr />

## Table of Contents


I don't know of the best way to show all of my code. I don't want to host it incase it changes later, so unfortunately the best way I can think of is to just slap it here in blocks.

But I am going to break it down into 5 parts.

1. [Imports](#imports)
 - The couple of imports we need for our page
2. [Styled Components](#styled-components)
 - Our Styled Components (done in file, not imported)
3. [HTML Structure](#html-structure)
 - Our HTML layout with content
4. [Props](#props)
 - Changes to our getStaticProps
5. [Preview](#preview)
 - Online sandbox so you can see how it should look or copy the `/pages/posts/[slug].js` file.

<hr />

## Imports

This can look different for you if you choose to use additional icons, I'm just importing 3 basic ones for now.

```javascript
import PortableText from "react-portable-text";
import styled from "styled-components";
import Link from "next/link";
import { BsFacebook, BsTwitter, BsInstagram } from "react-icons/bs";
```

We import.. 
- `PortableText` to display the `body` of our post.
- `styled` so we can create styled components.
- `Link` to navigate to the homepage or to other posts.
- The last line is importing a Facebook, Twitter, and Instagram icon from our `react-icons`.

<hr/ >

## Styled Components

> FYI: I only spent a little over an hour on the styling. It isn't perfect and some of the code is redundant, but I'm already behind on this project so I just wanted to get something that looked nice in browser.

### Before we get to the components, I added a couple things to our `/styles/globals.css` file.

```scss
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');

* {
  padding: 0;
  margin: 0;
  font-family: 'Poppins';
  color: #333;
}

body {
  background: rgb(248, 248, 248)
}

a {
  color: inherit;
  text-decoration: none;
}

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

- Poppins is now our default font for everything.
- `#333` is the default font color for everything.
- The `body` now has a background color of `rgb(248, 248, 248)`.
 - This is an off white color that is easier on the eyes.

Below your imports but above your `Post` component is where we will create our styling. Normally this is done in separate files, but since we aren't styling that many pages I don't see a reason to break it up.

I explained [Styled Components](https://dev.to/zacherymorgan/setting-up-nextjs-with-styled-components-355j#installing-styled-components) very briefly at the start of these guides, but I will go over 1 I created for this page as a refresher.

> Do not copy this into your file yet, it will be included in the full list of components I will post after this explanation.

```javascript
const BackButton = styled.div`
  border: 1px solid #333;
  border-radius: 7px;
  text-align: center;
  font-size: 1.2rem;
  width: fit-content;
  padding: 4px 6px;
  transition: all 0.3s;

  :hover {
    background: #333;
    color: white;
    cursor: pointer;
  }

  span {
    position: relative;
    bottom: 3px;
  }
`;
```

- First we create a component with the name of `BackButton`
 - This is a React component so it must be Pascal case (each word capital).

- We declare that this component is a `styled.div`
 - `styled.` is from our import
 - `div` is letting React know what kind of HTML element we are assigning. in this case it will be a `<div></div>`
 - All you have to do to use it is replace `<div></div>` in your code for `<BackButton></BackButton>` and it will now be a `div` element with styling.

- You also need to be aware that we are wrapping the CSS for our component in backticks.

- Now inside is our basic CSS. I'm not going to go over the details of my CSS, or how I'm using `grid` for positioning because it's better for you to play around with it and find out yourself. But if you still do not understand the purpose of a line, you can either Google it, play around with it in your Browser DevTools, or even shoot me a message on [Twitter](https://twitter.com/ZacherySMorgan) and I can help explain further.
 - We apply styling to our `div` element
 - What happens when the `div` is `hovered`
 - And finally we apply styling to any `span` elements inside of this div.


After that quick example, here is the entire block of code for all of our styling. Remember, paste this below your imports and above your `Post` component.

```javascript
const PageContainer = styled.div`
  padding: 70px 110px;
  max-width: 1600px;
  margin-inline: auto;
`;

const BackButton = styled.div`
  border: 1px solid #333;
  border-radius: 7px;
  text-align: center;
  font-size: 1.2rem;
  width: fit-content;
  padding: 4px 6px;
  transition: all 0.3s;

  :hover {
    background: #333;
    color: white;
    cursor: pointer;
  }

  span {
    position: relative;
    bottom: 3px;
  }
`;

const ContentContainer = styled.div`
  display: grid;
  grid-template-columns: 0.5fr 2fr 1fr;
  grid-template-rows: 1fr auto;
  grid-template-areas:
    "header1 header header2"
    "socials main links";
`;

const Header = styled.header`
  grid-area: header;
  text-align: center;
  margin-bottom: 40px;

  h1 {
    text-transform: uppercase;
    color: #222222;
    font-size: 3rem;
  }

  span {
    color: #464646;
  }
`;

const SocialsContainer = styled.ul`
  grid-area: socials;
  display: flex;
  flex-direction: column;
  align-items: end;
  list-style-type: none;
  gap: 30px;
  padding-right: 50px;
  padding-top: 14px;

  li {
    cursor: pointer;
  }
`;

const StyledLi = styled.li`
  svg {
    transition: transform 0.4s;

    path {
      color: #4040ac;
    }
  }

  svg:hover {
    transform: scale(1.2);
  }
`;

const Body = styled.main`
  grid-area: main;

  h1 {
    text-align: center;
    font-size: 2.3rem;
    margin-bottom: 15px;
    padding-right: 160px;
  }

  h2 {
    margin: 5px 0px;
  }

  div {
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
`;

const RecentPostsContainer = styled.div`
  padding-left: 50px;
  grid-area: links;
  display: flex;
  flex-direction: column;
  gap: 20px;
`;

const RecentPost = styled.div`
  display: flex;
  flex-direction: column;
  border: 1px solid #333;
  align-items: center;
  transition: all 0.4s;

  p {
    font-size: 1.1rem;
    font-weight: 500;
  }

  span,
  p {
    transition: all 0.4s;
  }

  :hover {
    background: #333;
    cursor: pointer;

    span,
    p {
      color: white;
    }
  }
`;
```

> I'm styling the `post.body` content from within the `Body` component. 
> As you can see I only targeted `h1`, `h2`, and `div` because those are what I have inside of my post's body. If you have other elements you can style them how you see fit, by targeting the type of the element and applying your style.

<hr />

## HTML Structure

Pasting all of that in won't do a darn thing until you add these components to your code. 

> Remember, your code will break because I changed how we import our posts. That will be explained next.

```javascript
export default function Post({ post, posts }) {
  const postsElements = posts.map((post, index) => (
    <Link key={index} href={`/posts/${post.slug}`}>
      <RecentPost>
        <p>{post.title}</p>
        <span>{new Date(post.publishedAt).toDateString().slice(4)}</span>
      </RecentPost>
    </Link>
  ));

  return (
    <PageContainer>

      <Link href={`/`}>
        <BackButton>
          <span>👈</span>
          <a>Home</a>
        </BackButton>
      </Link>

      <ContentContainer>

        <Header>
          <span>{new Date(post.publishedAt).toDateString()}</span>
          <h1>{post.title}</h1>
        </Header>

        <SocialsContainer>
          <StyledLi>
            <a href="https://facebook.com">
              <BsFacebook size={"3rem"} />
            </a>
          </StyledLi>
          <StyledLi>
            <a href="https://twitter.com">
              <BsTwitter size={"3rem"} />
            </a>
          </StyledLi>
          <StyledLi>
            <a href="https://instagram.com">
              <BsInstagram size={"3rem"} />
            </a>
          </StyledLi>
        </SocialsContainer>

        <Body>
          <PortableText content={post.body} />
        </Body>

        <RecentPostsContainer>
          {postsElements}
        </RecentPostsContainer>

      </ContentContainer>

    </PageContainer>
  );
}
```

This is pretty simple, we are using our Styled Components we just created instead of normal HTML elements.

I will point out the couple of things that are important to take note of here.

```javascript
export default function Post({ post, posts })
```
 - You can see we are now importing `post` AND `posts`. You will see why in a second.

```javascript
const postsElements = posts.map((post, index) => (
    <Link key={index} href={`/posts/${post.slug}`}>
      <RecentPost>
        <p>{post.title}</p>
        <span>{new Date(post.publishedAt).toDateString().slice(4)}</span>
      </RecentPost>
    </Link>
  ));
```
 - We are mapping over the posts we fetch to create a list of links to every post (excluding the post we are currently viewing).

```javascript
<BsFacebook size={"3rem"} />
```
 - React Icons are styled by this `size` attribute so we have these on each one to increase them to `3rem`.

```javascript
<Body>
    <PortableText content={post.body} />
</Body>
```
 - You can see our `PortableText` we imported being used to display the `body` of our post by adding it as the `content`.
 - It's annoying to style `PortableText`, so I just surround it in a styled div and apply the styling there.

```javascript
<RecentPostsContainer>{postsElements}</RecentPostsContainer>
```
 - And finally our `postsElements` variable we created being surrounded by a styled component.

<hr />

## Props

I came up with the idea to display all of our blog posts in the right sidebar. Before we were only fetching our current post, but now we need to fetch all of them as well.

```javascript
export async function getStaticProps({ params }) {
  const query = `*[_type == "post"] {
    _id,
    title,
    publishedAt,
    'slug': slug.current,
    body
  }`;

  let posts = await client.fetch(query);

  const post = await posts.find((post) => post.slug == params.slug);

  posts.splice(
    posts.indexOf(posts.find((post) => post.slug == params.slug)),
    1
  );

  return {
    props: { posts, post },
  };
}
```

Not a lot changed, but I'll explain the general idea of it.

- We no longer fetch just the current post, we now get every single entry with a type of `post`.

- After all of our posts are returned, we run a `find` method to match the post in our array the contains the same `slug` as our url params.

- Then we `splice` out the post we just fetched because we don't want to display that one in our list of posts on the side.

- Finally we return all of our `posts` excluding our current post, and our current `post`.

<hr />

## Preview

[CodeSandbox Code](https://codesandbox.io/s/bitter-pine-e2qivf?file=/src/App.js) -- [Fullscreen Preview](https://e2qivf.csb.app/)
Here you can view my code, there are some changes to remove fetching and the file structure is obviously incorrect. This is supposed to just be a reference to how the page and `/pages/posts/[slug].js` code should look for you (minus the slight changes).

That's the end of this part. We didn't alter our project too much, but we now have a great looking page to display each of our posts.

I know that was a lot of code, and there is always a possibility something goes wrong on your end. So if there is something you just cannot seem to fix, send me a message on [Twitter](https://twitter.com/ZacherySMorgan) and I will help you out as much as I can.

<hr />

## Next Lesson

I think I will skip styling the homepage for now. It would be a fantastic exercise to practice styled components.

At the end of the tutorial I'll have a link to this project which will include my personal styling if you are interested in that.

The next few lessons are going to be less code oriented and more involved with using Vercel, GitHub, and Sanity utilities.
Our goal is to...

1. Push our code to GitHub.

2. Deploy our website on Vercel.

3. Deploy our Sanity Studio interface to Vercel.

### Thank you to everyone who has read these lessons!