How we developed our company website using NextJS
Tags: webdev, programming, javascript, nextjs
Published: 2022-10-17 06:17:51

---
canonical_url: https://josemukorivo.com/blog/how-we-developed-our-company-website-using-nextjs-2ga5
---

I sat down with my close friends that I had been working with for a while at the start of 2022 to discuss about starting a software company that merged aesthetics and functionality. We made the decision to combine our various skill sets to form that business, and [complexus](https://complexus.tech) was established.

We completed a few [projects](https://complexus.tech/projects) for other clients before deciding to concentrate on our website. We began by conducting research on our target market, and then the team began to work on the initial iteration of the site's design.

## Overview
In this article, I'll primarily discuss the tools we utilized and how we used them to create our dynamic website. These are the tools we typically employ for our clients' projects.

{% embed https://youtu.be/yhCsf5cmYiY %}


## Design
The design team used figma to create the site's design, and a screenshot of the initial version is seen below. The design was finished after four iterations, the first of which was a low-fidelity wireframe. Almost everyone contributed to the design in some way.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dag7itgatzwhq4qpcq8k.png)


## Content
We had someone in charge of copywriting for the site's material, and they collaborated with the design team to ensure that what they were writing was consistent with the design.

## Development
We went on to build the website after creating the design and the content. Let me list some of the things that the website is powered by before I get into the technicalities.


1. [React](https://reactjs.org/) for the UI
2. [NextJS](https://nextjs.org) for SSG/SSR/ISSG
3. [Tailwind css](https://tailwindcss.com) for styling
4. [CSS modules](https://github.com/css-modules/css-modules) styling without class name collision
5. [GSAP](https://greensock.com/gsap/) JavaScript animations
6. [Mailchimp](https://mailchimp.com) for the mailing list
7. [Vercel](https://vercel.com) CI/CD and hosting
8. [Framer motion](https://www.framer.com/motion/) JavaScript animations
9. [TypeScript](https://www.typescriptlang.org/) for adding type safety to our codebase

I will probably spend a little more time at this stage because development was the most fascinating phase. [Reactjs](https://reactjs.org/) is the foundation of the website and all the components were built upon it. Below is a sample reusable `Button` component and its styles.

##### Button.tsx

```tsx
import {
  FC,
  forwardRef,
  ButtonHTMLAttributes,
  JSXElementConstructor,
  ReactElement,
} from 'react';
import Link from 'next/link';
import { motion } from 'framer-motion';
import cn from 'classnames';

import s from './Button.module.scss';

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  href?: string;
  className?: string;
  disabled?: boolean;
  rightIcon?: ReactElement;
  leftIcon?: ReactElement;
  active?: boolean;
  target?: '_blank' | '_self' | '_parent' | '_top';
  size?: 'sm' | 'md' | 'lg';
  variant?:
    | 'primary'
    | 'secondary'
    | 'white'
    | 'black'
    | 'naked'
    | 'outlineBlack'
    | 'outlineWhite'
    | 'square';
  as?: 'button' | 'a' | JSXElementConstructor<any>;
}

export const Button: FC<ButtonProps> = forwardRef((props, buttonRef) => {
  const {
    as: Tag = 'button',
    variant = 'primary',
    size = 'md',
    target = '_self',
    href,
    active,
    rightIcon,
    leftIcon,
    className,
    disabled,
    children,
    ...rest
  } = props;
  const classes = cn(
    s.root,
    {
      [s.primary]: variant === 'primary',
      [s.outlineBlack]: variant === 'outlineBlack',
      [s.outlineWhite]: variant === 'outlineWhite',
      [s.secondary]: variant === 'secondary',
      [s.white]: variant === 'white',
      [s.naked]: variant === 'naked',
      [s.black]: variant === 'black',
      [s.square]: variant === 'square',
      [s.md]: size === 'md',
      [s.sm]: size === 'sm',
      [s.lg]: size === 'lg',
      'flex items-center gap-3': (rightIcon || leftIcon) && size === 'md',
      [s.dFlex]: (rightIcon || leftIcon) && size === 'lg',
      [s.active]: active,
    },
    className
  );

  return (
    <motion.span
      className='inline-block'
      initial={{ y: 10, opacity: 0 }}
      transition={{
        duration: 1,
        type: 'spring',
        damping: 5,
      }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, amount: 0.5 }}
    >
      {href ? (
        <Tag {...rest}>
          <Link href={href}>
            <a className={classes} target={target}>
              {leftIcon}
              <span>{children}</span>
              {rightIcon}
            </a>
          </Link>
        </Tag>
      ) : (
        <Tag disabled={disabled} className={classes} {...rest}>
          {leftIcon}
          <span>{children}</span>
          {rightIcon}
        </Tag>
      )}
    </motion.span>
  );
});

Button.displayName = 'Button';

```

##### Button.module.scss
```css
.root {
  @apply mb-1 transition duration-200 ease-linear;
}

.dFlex {
  @apply flex items-center gap-5;
}

.primary {
  @apply relative overflow-hidden border border-primary bg-primary text-white;

  span,
  svg {
    @apply relative z-[2];
  }

  &::after {
    content: '';
    @apply absolute top-0 left-0 block h-full w-0 bg-white transition-[width] duration-300 ease-linear;
  }

  &:hover {
    @apply text-primary;
  }

  &:hover::after {
    @apply w-full;
  }
}

.naked {
  @apply bg-transparent;
}

.black {
  @apply relative border border-black bg-black text-white;

  &::after {
    content: '';
    @apply absolute top-0 left-0 block h-full w-0 bg-white mix-blend-difference transition-[width] duration-300 ease-linear;
  }
  &:hover::after {
    @apply w-full;
  }
}

.white {
  @apply border border-white bg-white text-primary;
}

.secondary {
  @apply border border-secondary bg-secondary text-white;
}

.outlineBlack {
  @apply relative border border-black;

  &::after {
    content: '';
    @apply absolute top-0 left-0 block h-full w-0 bg-white mix-blend-difference transition-[width] duration-300 ease-linear;
  }
  &:hover::after {
    @apply w-full;
  }
}

.square {
  @apply relative flex h-12 w-12 items-center justify-center rounded-full border border-black p-0 hover:scale-110 3xl:h-20 3xl:w-20 3xl:border-2 #{!important};
}

.outlineWhite {
  @apply relative border border-white text-white;

  &::before {
    content: '';
    @apply absolute left-[20%] -bottom-[1px] h-[1px] w-7 bg-black transition-[left];
  }

  &::after {
    content: '';
    @apply absolute right-[20%] -top-[1px] h-[1px] w-7 bg-black transition-[right];
  }

  &:hover::before {
    @apply left-[30%];
  }
  &:hover::after {
    @apply right-[30%];
  }

  &:hover {
    @apply opacity-100;
  }
}

.sm {
  @apply px-4 py-2;
}

.md {
  @apply px-4 py-[10px] xl:px-6;
}

.lg {
  @apply px-5 py-4 text-sm font-medium xl:py-[1.1rem] xl:px-8 xl:text-base 3xl:px-16 3xl:py-6 3xl:text-lg;
}

```

The components were code using TypeScript for type safety. TypeScript also helps with writing code that is self documenting. For styling we went with `tailwindcss` but note that classes in our react components are clean because the tailwind utility classes are in a separate css file which is a `CSS module`. CSS modules helps in avoiding namespace collision for CSS classes. Below will be how the `Button` can be used.

```tsx
<Button
  variant='black'
  size='lg'
  href='/contact'
  className='relative ml-2'
  rightIcon={<Line />}
>
  Get in touch
</Button>
```
All of our reusable components are coded this way.

These small components like the `Button`, `Text`, `Link` and `Box` are located in the `components/ui/` folder and exported using using a single `index.ts` file so that they can be imported like so 

```ts
import { Text, Box, Container, Link, Button } from '@components/ui';
```

Common elements like the `Navigation` and `Footer` are in the `components/shared/` folder and elements that are specific to a page are in the `components/pages/[page-name]` folder.

### SEO
We had to make sure that our website is search engine friendly so we created a `Page` component that takes some SEO data as props and every page on the site uses it as a parent.

##### Page.tsx
```tsx
import { FC } from 'react';
import Head from 'next/head';

interface Props {
  title: string;
  description: string;
  image: string;
  canonicalURL?: string;
}

export const Page: FC<Props> = ({
  children,
  title,
  description,
  image,
  canonicalURL,
}) => {
  return (
    <>
      <Head>
        <title>{title}</title>
        <meta name='description' content={description} />
        <meta name='author' content='Complexus Technologies' />
        <meta name='image' content={image} />
        <meta name='og:title' content={title} />
        <meta name='og:description' content={description} />
        <meta name='og:image' content={image} />
        <meta name='og:url' content='https://complexus.tech' />
        <meta name='og:site_name' content='Complexus Technologies' />
        <meta name='og:type' content='website' />
        <meta name='twitter:card' content='summary_large_image' />
        <meta name='twitter:title' content={title} />
        <meta name='twitter:alt' content={title} />
        <meta name='twitter:description' content={description} />
        <meta name='twitter:image' content={image} />
        <meta name='theme-color' content='#f43f5e' />
        <meta name='twitter:site' content='@complexus_tech' />
        <meta name='twitter:creator' content='@complexus_tech' />
        {canonicalURL && <link rel='canonical' href={canonicalURL} />}
      </Head>
      <main>{children}</main>
    </>
  );
};

```

##### Example Page usage
```tsx
import type { NextPage } from 'next';
import { Page, HowMuch } from '@components/shared';
import { Hero, Intro, Team } from '@components/pages/about';

const Home: NextPage = () => {
  return (
    <Page
      title='About | Complexus Technologies'
      description='Complexus helps you achieve your business goals through effective planning, design, and development.'
      image='https://complexus.tech/images/banner.jpg'
      url='https://complexus.tech/about/'
      canonicalURL='https://complexus.tech/about/'
      keywords='complexus, complexus technologies, complex, zimbabwe sofware company, mobile development, it consultancy'
    >
      <Hero />
      <Intro />
      <Team />
      <HowMuch />
    </Page>
  );
};

export default Home;
```

We also used other tools like Google Analytics, Google My Business and Google search console for SEO.
We also used some open graph tags to make sure that the site has some nice priviews when we share it on social media.


## Mailing list
In order to share some information about events at Complexus, we are running a mailing list using [Mailchimp](https://mailchimp.com/). If you subscribe we'd be grateful😎.

## Hosting
The website is hosted on [Vercel](https://vercel.com) and it rebuilds every time we push to the main branch on github.

## CTA
If your organization would like to have a website similar to ours, please contact us [here](complexus.tech/contact) or email us at <a href="mailto:hello@complexus.tech" target="_blank">hello@complexus.tech</a>. We also do custom software development check our services [here](complexus.tech/services).