How To Make Resume With React

November 20, 2022

3 min read

How To Make Resume With React
Watch on YouTube

Let's make a resume with React that you can turn into a one-page PDF to find a remote job. If you are curious about advice on how to make a resume for remote work, check out this post.


The container has a fixed width and aspect ratio of an A4 page to print the resume onto a single page. To separate sections of the page, we make the container a flexbox element with a background of a separator color while making children that will take the remaining space a black or white color depending on a selected theme. While printing, we want to remove the border and border-radius and make the content take up the whole space of the page by using media print.

import { defaultBorderRadiusCSS } from "lib/ui/borderRadius"
import styled from "styled-components"

export const ResumeContainer = styled.div`
  width: 880px;
  aspect-ratio: 1 / 1.414;

  display: flex;
  flex-direction: column;
  gap: 2px;
  background: ${({ theme }) => theme.colors.foreground.toCssValue()};
  border: 2px solid ${({ theme }) => theme.colors.foreground.toCssValue()};

  overflow: hidden;

  > * {
    background: ${({ theme }) => theme.colors.background.toCssValue()};
    padding: 20px;

  @media print {
    width: 100%;
    height: 100%;
    border-radius: 0;
    border: none;

To get a PDF, we use ReactToPrint, which will convert the content when we press the download button.

We start the resume with a summary that consists of two lines. To separate elements, we use the SeparatedBy component that goes over every child and puts a passed React element between them.

import styled from "styled-components"
import { StickyIconButton } from "lib/ui/buttons/square/StickyIconButton"
import ReactToPrint from "react-to-print"
import { DownloadIcon } from "lib/ui/icons/DonwloadIcon"
import { ReactInstance } from "react"

interface Props {
  renderContent: () => ReactInstance | null

const PrintButton = styled(StickyIconButton)`
  @media print {
    display: none;

export const PrintResume = ({ renderContent }: Props) => (
    trigger={() => <PrintButton icon={<DownloadIcon />} />}
import { ComponentWithChildrenProps } from "lib/shared/props"
import React, { Fragment } from "react"

import { HStack } from "./Stack"
import { Text } from "./Text"

export const dotSeparator = "•"
export const slashSeparator = "/"

interface Props extends ComponentWithChildrenProps {
  separator?: string
  gap?: number

export const SeparatedBy = ({ children, separator, gap = 8 }: Props) => {
  const definedChildren = React.Children.toArray(children).filter(
    (child) => child
  return (
    <HStack alignItems="center" gap={gap}>
      {, index) => {
        if (index === definedChildren.length - 1) {
          return child

        return (
          <Fragment key={index}>
            <Text color="supporting" as="div">

After that, we continue with lists of experience where the first one shows the most recent work, the second one older job positions, and the last one - side projects.

The JobExperience component receives position, company, start and end dates, and the list of responsibilities with technologies to render a summary of work at a given position. To show a personal project, we use a similar component that doesn't have the start and end dates but receives an achievement, description, and URL. Finally, we include a footer with links to email, Twitter, Github and Telegram.