Tips

Using PagedJS with Nuxt

Using PagedJS with Nuxt

Using PagedJS with Nuxt

Create a nice PDF with nuxt and PagedJS

Doppio Nuxt PDF Machine
Doppio Nuxt PDF Machine

Set up a Nuxt project

First, let's make a new Nuxt project.

npx nuxi@latest init <project-name

Then follow the instructions from your terminal.

Or you can follow the installation instructions from the official Nuxt documentation.


Install the pagedjs npm module

The pagedjs library is available through a script, a command line or a npm module. We'll focus on the npm module here but feel free to go check their documentation for more solutions.

Install the pagedjs npm module.

npm install --save pagedjs


Create a new component

Let's create a new component to display our PDF.

Create a new directory called components in your project root and add a new file pdf.vue with the following code.

<template>
  <div class="App">
    <section class="chapter" id="about-page">
      <h2 class="title" id="label-title">About</h2>
      <p class="text">
        Lorem ipsum dolor sit amet consectetur adipiscing elit. Duis nibh tortor
      </p>
    </section>

    <section class="chapter" id="chapter1-page">
      <h2 class="title">Chapter 1</h2>
      <p class="text">Lorem ipsum dolor sit amet</p>
    </section>

    <section class="chapter" id="chapter2-page">
      <h2 class="title">Chapter 2</h2>
      <p class="text">consectetur adipiscing elit</p>
    </section>

    <section class="chapter" id="chapter3-page">
      <h2 class="title">Chapter 3</h2>
      <p class="text">Duis nibh tortor, pellentesque eu suscipit vel</p>
    </section>
  </div>
</template>

In your app.vue file, add the pdf component to the template.

<template>
  <div>
    <pdf />
  </div>
</template>


Setup PagedJS

We'll use the Previewer from pagedjs to display our page as a PDF.
First, import the Previewer from pagedjs npm module by adding it in the script of your component.

import { Previewer } from 'pagedjs';

Then, add a onMounted hook to call the method when the component is mounted.

onMounted(() => {
  startPreview();
});

Don't forget to import onMounted from vue.

import { onMounted } from 'vue';

This is what the function startPreview looks like (pagedjs documentation is here).

const startPreview = () => {
  const previewer = new Previewer();
  previewer.preview().then((flow: any) => {
    console.log('Rendered', flow.total, 'pages.');
  });
};

To summarize, your pdf.vue component should look like this.

<template>
  <div class="App">
    <section class="chapter" id="about-page">
      <h2 class="title" id="label-title">About</h2>
      <p class="text">
        Lorem ipsum dolor sit amet consectetur adipiscing elit. Duis nibh tortor
      </p>
    </section>

    <section class="chapter" id="chapter1-page">
      <h2 class="title">Chapter 1</h2>
      <p class="text">Lorem ipsum dolor sit amet</p>
    </section>

    <section class="chapter" id="chapter2-page">
      <h2 class="title">Chapter 2</h2>
      <p class="text">consectetur adipiscing elit</p>
    </section>

    <section class="chapter" id="chapter3-page">
      <h2 class="title">Chapter 3</h2>
      <p class="text">Duis nibh tortor, pellentesque eu suscipit vel</p>
    </section>
  </div>
</template>

<script setup lang="ts">
  import { Previewer } from 'pagedjs';
  import { onMounted } from 'vue';

  onMounted(() => {
    startPreview();
  });

  const startPreview = () => {
    const previewer = new Previewer();
    previewer.preview().then((flow: any) => {
      console.log('Rendered', flow.total, 'pages.');
    });
  };
<


Styling the page

Now you are ready to add style for pagedjs to create your beautiful PDF.
Start by creating an assets folder in your project root and a new folder css inside it. Add a new file style.css with the following code.

.App {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 2rem 4rem;
  box-shadow: 0 0 0 1px grey;
}

h2 {
  text-align: center;
  color: #3c3c3c;
}

p {
  text-align: center;
  color: #a1a1a1;
}

Then, import the css file in your component style.

<style>
  @import url('~/assets/css/style.css');
</style>


Display custom content through "named strings"

What if you want to display the name of the chapter you are in at the bottom of the PDF ?
Let's add the following css to the style.css file.

@page {
  @bottom-center {
    content: string(title);
  }
}

.chapter > h2 {
  string-set: title content(text);
}

The first block, is used to tell pagedjs to add content in the margin of the PDF, at the bottom center position (check all the positions available).
The second block, is used to make available the title of the chapter to pagedjs, we use the named strings feature from pagedjs to give the content of the h2 tag from every chapter into the named string title.


Display custom content through HTML attributes

It is also possible to display content in the PDF declaring custom attributes into the HTML.
First, to every section tag in your component, add a custom attribute data-* where you replace * with whatever name you want to give to your content.
For example adding a data-reference to every chapter.

<div class="App">
  <section class="chapter" id="about-page" data-reference="001">
    <h2 class="title" id="label-title">About</h2>
    <p class="text">
      Lorem ipsum dolor sit amet consectetur adipiscing elit. Duis nibh tortor
    </p>
  </section>

  <section class="chapter" id="chapter1-page" data-reference="002">
    <h2 class="title">Chapter 1</h2>
    <p class="text">Lorem ipsum dolor sit amet</p>
  </section>

  <section class="chapter" id="chapter2-page" data-reference="003">
    <h2 class="title">Chapter 2</h2>
    <p class="text">consectetur adipiscing elit</p>
  </section>

  <section class="chapter" id="chapter3-page" data-reference="004">
    <h2 class="title">Chapter 3</h2>
    <p class="text">Duis nibh tortor, pellentesque eu suscipit vel</p>
  </section>
</div>

Then, add the following to your style.css file.

@page {
  @right-middle {
    content: string(ref);
  }
}
.chapter {
  string-set: ref attr(data-reference);
}

The first block, is used to tell pagedjs where to display the content (just as before, you can check all the positions available).
The second block, is used to make available the reference to pagedjs, we use the generated text feature from pagedjs.


What's next

Be sure to check the pagedjs documentation to see all the features available and how you can use them to render beautiful PDFs !

Set up a Nuxt project

First, let's make a new Nuxt project.

npx nuxi@latest init <project-name

Then follow the instructions from your terminal.

Or you can follow the installation instructions from the official Nuxt documentation.


Install the pagedjs npm module

The pagedjs library is available through a script, a command line or a npm module. We'll focus on the npm module here but feel free to go check their documentation for more solutions.

Install the pagedjs npm module.

npm install --save pagedjs


Create a new component

Let's create a new component to display our PDF.

Create a new directory called components in your project root and add a new file pdf.vue with the following code.

<template>
  <div class="App">
    <section class="chapter" id="about-page">
      <h2 class="title" id="label-title">About</h2>
      <p class="text">
        Lorem ipsum dolor sit amet consectetur adipiscing elit. Duis nibh tortor
      </p>
    </section>

    <section class="chapter" id="chapter1-page">
      <h2 class="title">Chapter 1</h2>
      <p class="text">Lorem ipsum dolor sit amet</p>
    </section>

    <section class="chapter" id="chapter2-page">
      <h2 class="title">Chapter 2</h2>
      <p class="text">consectetur adipiscing elit</p>
    </section>

    <section class="chapter" id="chapter3-page">
      <h2 class="title">Chapter 3</h2>
      <p class="text">Duis nibh tortor, pellentesque eu suscipit vel</p>
    </section>
  </div>
</template>

In your app.vue file, add the pdf component to the template.

<template>
  <div>
    <pdf />
  </div>
</template>


Setup PagedJS

We'll use the Previewer from pagedjs to display our page as a PDF.
First, import the Previewer from pagedjs npm module by adding it in the script of your component.

import { Previewer } from 'pagedjs';

Then, add a onMounted hook to call the method when the component is mounted.

onMounted(() => {
  startPreview();
});

Don't forget to import onMounted from vue.

import { onMounted } from 'vue';

This is what the function startPreview looks like (pagedjs documentation is here).

const startPreview = () => {
  const previewer = new Previewer();
  previewer.preview().then((flow: any) => {
    console.log('Rendered', flow.total, 'pages.');
  });
};

To summarize, your pdf.vue component should look like this.

<template>
  <div class="App">
    <section class="chapter" id="about-page">
      <h2 class="title" id="label-title">About</h2>
      <p class="text">
        Lorem ipsum dolor sit amet consectetur adipiscing elit. Duis nibh tortor
      </p>
    </section>

    <section class="chapter" id="chapter1-page">
      <h2 class="title">Chapter 1</h2>
      <p class="text">Lorem ipsum dolor sit amet</p>
    </section>

    <section class="chapter" id="chapter2-page">
      <h2 class="title">Chapter 2</h2>
      <p class="text">consectetur adipiscing elit</p>
    </section>

    <section class="chapter" id="chapter3-page">
      <h2 class="title">Chapter 3</h2>
      <p class="text">Duis nibh tortor, pellentesque eu suscipit vel</p>
    </section>
  </div>
</template>

<script setup lang="ts">
  import { Previewer } from 'pagedjs';
  import { onMounted } from 'vue';

  onMounted(() => {
    startPreview();
  });

  const startPreview = () => {
    const previewer = new Previewer();
    previewer.preview().then((flow: any) => {
      console.log('Rendered', flow.total, 'pages.');
    });
  };
<


Styling the page

Now you are ready to add style for pagedjs to create your beautiful PDF.
Start by creating an assets folder in your project root and a new folder css inside it. Add a new file style.css with the following code.

.App {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 2rem 4rem;
  box-shadow: 0 0 0 1px grey;
}

h2 {
  text-align: center;
  color: #3c3c3c;
}

p {
  text-align: center;
  color: #a1a1a1;
}

Then, import the css file in your component style.

<style>
  @import url('~/assets/css/style.css');
</style>


Display custom content through "named strings"

What if you want to display the name of the chapter you are in at the bottom of the PDF ?
Let's add the following css to the style.css file.

@page {
  @bottom-center {
    content: string(title);
  }
}

.chapter > h2 {
  string-set: title content(text);
}

The first block, is used to tell pagedjs to add content in the margin of the PDF, at the bottom center position (check all the positions available).
The second block, is used to make available the title of the chapter to pagedjs, we use the named strings feature from pagedjs to give the content of the h2 tag from every chapter into the named string title.


Display custom content through HTML attributes

It is also possible to display content in the PDF declaring custom attributes into the HTML.
First, to every section tag in your component, add a custom attribute data-* where you replace * with whatever name you want to give to your content.
For example adding a data-reference to every chapter.

<div class="App">
  <section class="chapter" id="about-page" data-reference="001">
    <h2 class="title" id="label-title">About</h2>
    <p class="text">
      Lorem ipsum dolor sit amet consectetur adipiscing elit. Duis nibh tortor
    </p>
  </section>

  <section class="chapter" id="chapter1-page" data-reference="002">
    <h2 class="title">Chapter 1</h2>
    <p class="text">Lorem ipsum dolor sit amet</p>
  </section>

  <section class="chapter" id="chapter2-page" data-reference="003">
    <h2 class="title">Chapter 2</h2>
    <p class="text">consectetur adipiscing elit</p>
  </section>

  <section class="chapter" id="chapter3-page" data-reference="004">
    <h2 class="title">Chapter 3</h2>
    <p class="text">Duis nibh tortor, pellentesque eu suscipit vel</p>
  </section>
</div>

Then, add the following to your style.css file.

@page {
  @right-middle {
    content: string(ref);
  }
}
.chapter {
  string-set: ref attr(data-reference);
}

The first block, is used to tell pagedjs where to display the content (just as before, you can check all the positions available).
The second block, is used to make available the reference to pagedjs, we use the generated text feature from pagedjs.


What's next

Be sure to check the pagedjs documentation to see all the features available and how you can use them to render beautiful PDFs !

By Nathan Genaudeau

June 7, 2024