How to Create a Website Using React and Framer Motion: Complete Tutorial, Part 1

How to Create a Website Using React and Framer Motion: Complete Tutorial, Part 1
Time to read
6 min
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


Hey there! We are coming back with a second tutorial for enthusiastic developers. In this series of articles, we will try to create an engaging website using React with Vite, Typescript, SCSS, and Framer Motion.

We will answer some of the questions, starting from the basics up to various hints and tricks that you may need for your product.

Here is a quick breakdown of the topics that we are going to cover in this tutorial: 

  • Project init, React+Vite, Typescript, and SCSS
  • How to add custom fonts and other media
  • How to add types and constants
  • Basic layout: navbar, logo, arrow, burger
  • Buttons to switch between period and subject
  • How to add images to the newly created website
  • Optimizations: images, lighthouse, cache, preload images

Let us start!

Project init, React+Vite, Typescript, SCSS

For this project, we will be using React with Vite, Typescript, SCSS, and Framer Motion

If you already have a basic project template or you’re using another tool for project creation, you can skip this step.

  1. Let’s start with project creation via Vite. For that, you’ll need to run

    npm create vite@latest
  2. Choose a name for the project
  3. Select React from the list of frameworks
  4. Select TypeScript
  5. When initialization is complete, select your newly created project and then run
    npm install
  6. To use SCSS for the project, we have to install the SASS package
    npm install --save-dev sass
  7. We’ll need clsx for effective classNames management

    npm install --save clsx
  8. svgr to convert svg images to react components
    npm install --save svgr
  9. And we need a library to make animations and transitions. We’ll use Framer Motion for this
    npm install framer-motion
  10. Now you should be able to run the project with
    npm run dev 

    which will show you a basic Vite starting page.

Adding custom fonts and other media

Now let’s add some assets. We’ll begin with fonts, and we will use three different ones: Roboto Serif, Roboto Slab, and Modernist

/* ./src/styles/abstracts/fonts.scss */

@font-face {
  font-family: 'RobotoSerif-RegularItalic';
  font-display: swap;
  src: local('RobotoSerif-RegularItalic'), url(../../assets/fonts/RobotoSerif/RobotoSerif-RegularItalic.ttf) format('truetype');


Notice that we use font-display: swap. The font swap period occurs immediately after the font block period. During this period, if the font face is not loaded, any element attempting to use it must instead render with a fallback font face. If the font face successfully loads during the swap period, it is then used normally.

We’ll also add these fonts to the variables

/* ./src/styles/abstracts/variables.scss */

/* ... */
$font-italic-regular: 'RobotoSerif-RegularItalic';

$font-title-semi-bold: 'RobotoSlab-SemiBold';
$font-title-bold: 'RobotoSlab-Bold';
$font-title-extra-bold: 'RobotoSlab-ExtraBold';

$font-main-bold: 'SkModernist-Bold';
$font-main-regular: 'SkModernist-Regular';
/* ... */


Our website needs to support several different display resolutions, which is why we also add some breakpoints in variables for future usage

/* ./src/styles/abstracts/variables.scss */

/* … */
$break-points: (
  small: 600px,
  medium: 992px,
  large: 1350px,
/* … */


Images that we are going to use are stored in ./src/assets/images in PNG format for now; we will optimize them later

Let’s also reset some of the default browser styles:

/* ./src/styles/globas.scss */

@use './abstracts' as *;

*, *::after, *::before, {
  box-sizing: border-box;

html, body {
  padding: 0;
  margin: 0;
  background: $background;
  font-family: $font-main-regular;

h1, h2, h3, h4, p {
  margin: 0;

.home {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  overflow: hidden;

Adding types and constants

Now we need to define some TypeScript Interfaces, constants, and enums

Let’s start with the constants to define periods, countries, and subjects

// ./src/constants.ts

export enum Periods {
  Viking = 'Viking age',
  Assimilation = 'Assimilation',

export enum Countries {
  Norway = 'Norway',
  Sweden = 'Sweden',
  Denmark = 'Denmark',
  Norden = 'Norden',

export enum Subjects {
  History = 'History',
  Culture = 'Culture',


We need to define data interfaces for consistency, we’ll also use enums here from above. You can read more about Interfaces and Mapped types in Typescript documentation

// ./src/types.ts

import { Countries, Periods, Subjects } from './constants';

export interface PeriodItemInterface {
  name: Periods;
  primaryColor: string;
  secondaryColor: string;
  imagePath: string;
  quotationText: string;
  quotationAuthor: string;

export type PeriodsDataInterface = {
  [Key in Periods]: PeriodItemInterface;

export interface InfoItemInterface {
  primaryColor: string;
  secondaryColor: string;
  imagePath: string;
  textBlocks: {
    left: string[];
    right: string[];

type CountryDataInterface = {
  [Key in Countries]: InfoItemInterface;

type SubjectDataInterface = {
  [Key in Subjects]: CountryDataInterface;

export type DataInterface = {
  [Key in Periods]: SubjectDataInterface;


And then use these interfaces for our static data

// ./src/data.ts

export const periodsData: PeriodsDataInterface = {
  [Periods.Viking]: {
    name: Periods.Viking,
    primaryColor: '#B898FB',
    secondaryColor: '#3D006C',
    imagePath: VikingAgeImagePath,
      'The Vikings were a fascinating people...',
    quotationAuthor: 'Judith Jesch',

export const data: DataInterface = {
  [Periods.Viking]: {
    [Subjects.History]: {
      [Countries.Norway]: {
        primaryColor: '#2B766C',
        secondaryColor: '#982020',
        imagePath: VikingAgeHistoryNorwayImage,
        textBlocks: {
          left: [
            'The Viking Age is a period...',
            'The Viking Age began...',
          right: [
            'In Norway, the Viking Age...',



That’s it for today’s part of our tutorial. Let’s recap what we have done already: 

  • Started creating a project via Vite
  • Added custom fonts and other media
  • Added types and constants

That’s a great deal of work; well done! We will be proceeding with this project in Part 2 of this tutorial. See you soon!