---
title: "Certificate template for JavaScript — quario"
description: "A ready-made quario certificate of completion for JavaScript. Landscape A4, the modules covered, a signature line and a verification number. Copy the definition, point it at your records, and render to HTML, PDF, or Word."
url: "https://getquario.com/templates/certificate"
---

# Certificate template for JavaScript

A certificate is mostly white space and a name. What makes it worth generating rather than
hand-typing is the part under the name. The modules covered, the hours, the result, a number
somebody can verify. This is a ready-made quario certificate of completion — copy it, point it at
your records, and render to HTML, PDF, or Word. It’s laid out on landscape A4, and the paper is the
host’s choice, not the document’s.

## What it renders

This isn’t a screenshot. quario compiles the definition and data below, and `@quario/viewer` renders
them in your browser. That’s landscape A4, because it’s what this page’s host asked for. The PDF
button hands you the same certificate as real `@quario/pdf` bytes, one page, 841.89 × 595.28 points.
The definition asks for `serif`, `sans` and `mono`. The faces you see are this page’s own, handed to
the viewer and the PDF export as the same TrueType files. The DOCX button beside it hands the same
definition to `@quario/docx`, where Word paginates and resolves the faces itself:

*Preview: the page renders this definition and its sample data live, with downloads — [see it rendered](https://getquario.com/templates/certificate).*

## The template

The whole certificate is a definition — data you can version and review. The issuer line, the
headline, the holder’s name, the module table, the signature, and the verification line are all in
here. Nothing about this document lives in code. This is the exact file the preview above renders:

```json title="certificate.report.json"
{
  "data": "$.certificate.modules[*]",
  "aggregates": {
    "hours": "sum:=@.hours",
    "modules": "count"
  },
  "style": { "family": "serif", "size": 11 },
  "header": [
    { "type": "text", "value": "{{ $.input.certificate.issuer.name }}",
      "style": { "family": "mono", "size": 8, "bold": false, "uppercase": true, "color": "#989a97", "align": "center", "spaceAfter": 20 } },
    { "type": "text", "value": "Certificate of Completion",
      "style": { "size": 32, "bold": true, "color": "#1e1f22", "align": "center" } },
    { "type": "text", "value": "This certifies that",
      "style": { "family": "sans", "size": 10, "bold": false, "color": "#5e6062", "align": "center", "spaceBefore": 18 } },
    { "type": "text", "value": "{{ $.input.certificate.holder.name }}",
      "style": { "size": 24, "bold": false, "italic": true, "color": "#1e1f22", "align": "center" } },
    { "type": "text", "value": [{ "value": "has completed " }, { "value": "{{ $.input.certificate.course }}", "style": { "bold": true, "color": "#1e1f22" } }],
      "style": { "family": "sans", "size": 10, "bold": false, "color": "#5e6062", "align": "center", "spaceBefore": 6 } },
    { "type": "text", "value": [{ "value": "{{ $.input.certificate.from }}" }, { "value": " to " }, { "value": "{{ $.input.certificate.to }}" }],
      "style": { "family": "sans", "size": 10, "bold": false, "color": "#5e6062", "align": "center", "format": "date" } },
    { "type": "text", "value": "{{ $.hours }} hours of instruction across {{ $.modules }} modules",
      "style": { "family": "sans", "size": 10, "bold": false, "color": "#5e6062", "align": "center", "spaceAfter": 22 } }
  ],
  "detail": {
    "header": {
      "style": { "family": "mono", "size": 7, "uppercase": true, "color": "#989a97",
        "borderBottomWidth": 0.5, "borderBottomStyle": "solid", "borderBottomColor": "#1e1f22" }
    },
    "row": { "style": { "family": "sans", "size": 9, "color": "#5e6062" } },
    "columns": [
      { "header": "Module", "value": "{{ @.name }}", "width": 60 },
      { "header": { "value": "Hours", "style": { "align": "right" } }, "value": "{{ @.hours }}", "width": 15, "style": { "align": "right" } },
      { "header": { "value": "Result", "style": { "align": "right" } }, "value": "{{ @.result }}", "width": 25, "style": { "align": "right", "color": "#1e1f22" } }
    ],
    "total": {
      "style": { "family": "sans", "size": 9, "bold": true, "color": "#1e1f22", "align": "right", "paddingTop": 4,
        "borderTopWidth": 0.5, "borderTopStyle": "solid", "borderTopColor": "#1e1f22" },
      "rows": [
        {
          "cells": [
            { "value": "Overall", "style": { "align": "left" } },
            { "value": "{{ $.hours }}" },
            { "value": "{{ $.input.certificate.result }}" }
          ]
        }
      ]
    }
  },
  "footer": [
    {
      "type": "split",
      "style": { "spaceBefore": 40 },
      "slots": [
        { "type": "text", "value": "{{ $.input.certificate.signatory.name }}\n{{ $.input.certificate.signatory.role }}", "width": 32,
          "style": { "family": "sans", "size": 8, "color": "#5e6062", "paddingTop": 6,
            "borderTopWidth": 0.5, "borderTopStyle": "solid", "borderTopColor": "#1e1f22" } },
        { "type": "text", "value": "", "width": 36 },
        { "type": "text", "value": [{ "value": "Certificate No. {{ $.input.certificate.number }}\nIssued " }, { "value": "{{ $.input.certificate.issued }}" }],
          "style": { "family": "sans", "size": 8, "color": "#5e6062", "align": "right", "paddingTop": 6, "format": "date",
            "borderTopWidth": 0.5, "borderTopStyle": "solid", "borderTopColor": "#1e1f22" } }
      ]
    }
  ],
  "page": {
    "footer": [
      { "type": "text", "value": "Verify this certificate at {{ $.input.certificate.issuer.verify }}",
        "style": { "family": "mono", "size": 7, "color": "#989a97", "align": "center" } }
    ]
  }
}
```

The document sets itself in `serif` at the top, so the headline and the name inherit the face and
only state their size. The **report header** is where the size matters. That band carries a
headline default — bold, 14 point — above the document’s own `style`, so every item in it states
its own `size`. The lines that shouldn’t be bold say `"bold": false` outright. The module table
and the footer have no such default and simply say `sans` where they want it.

The rows are the modules. `$.hours` is a `sum` over them and `$.modules` a `count`. The line _32
hours across 4 modules_ comes from the same rows the table lists, and the _Overall_ row reads the
same sum. The certificate can’t claim hours the table doesn’t show. The course dates are three
styled runs — a date, the word _to_, a date. The line’s `"format": "date"` presents each as `8 Jun
2026 to 21 Aug 2026` under `en-IE`. The hours line is a separate item, so the kind leaves the
numbers in it alone. The course name is a bold run inside its own sentence, and that weight reaches
the PDF and the workbook, not only the HTML.

The signature and the certificate number are one split. Each slot wears a `borderTop` with the
text under it, and an empty slot between them holds the gap. A slot that renders nothing keeps its
width. The verification line is `page.footer`, so it sits on the paper’s baseline whatever the
header above it runs to.

## The data

A definition renders nothing on its own — you hand it a document. This is the sample the preview
above uses. `$.certificate.modules[*]` in the definition selects its rows, and `$.input` reads the
holder, the course, the signatory and the number:

```json title="certificate.data.json"
{
  "certificate": {
    "number": "QPA-2026-0142",
    "issued": "2026-08-28",
    "course": "Bookbinding Foundations",
    "from": "2026-06-08",
    "to": "2026-08-21",
    "result": "Pass with distinction",
    "holder": { "name": "Ada Brekelmans" },
    "issuer": { "name": "Quire Press Academy", "verify": "academy.quirepress.example/verify/QPA-2026-0142" },
    "signatory": { "name": "M. Duyvendak", "role": "Head of studio" },
    "modules": [
      { "name": "Paper grain, folding and gathering", "hours": 6, "result": "Pass" },
      { "name": "Sewing structures", "hours": 8, "result": "Distinction" },
      { "name": "Case binding, quarter cloth", "hours": 12, "result": "Distinction" },
      { "name": "Finishing and foil stamping", "hours": 6, "result": "Pass" }
    ]
  }
}
```

## Use it

```bash title="shell"
npm install quario @quario/pdf
```

The paper is a render option, not part of the document. `size` takes a `[width, height]` in points,
and landscape A4 is portrait A4 turned round:

```ts title="certificate.ts"
import { writeFileSync } from 'node:fs'
import { quario } from 'quario'
import { pdf } from '@quario/pdf'
import certificate from './certificate.report.json' with { type: 'json' }

const report = quario({ locale: 'en-IE' }).report(certificate)

const data = await getCertificate(id)                // your records
const bytes = await report.render(pdf({ page: { size: [841.89, 595.28], margin: 64 } }), data)

writeFileSync('certificate.pdf', bytes)
```

Hand `pdf()` a `fonts` record and the certificate takes your own faces — the preview above
does exactly that. See [the PDF target](https://getquario.com/docs/diving-deeper/pdf-target.md) for embedding fonts.

## Make it yours

Because the certificate is declarative, changing it means changing data. A logo is an `image` item
whose `source` yields the bytes. A grade band is a `visible` expression on a line that only prints
for a distinction. A certificate of attendance drops the module table and keeps the header. A
batch is one definition and one data document per holder — the same file renders identically in
Node, the browser, and at the edge. It renders **without `eval`**, so a holder’s own name never
becomes code. [Security →](https://getquario.com/docs/diving-deeper/security.md)

## FAQ

### Can I generate the certificate as a PDF?

Yes, and it’s the format you send: `@quario/pdf` renders this definition straight to bytes, with
the faces you hand it embedded, and no browser anywhere. [Full example →](https://getquario.com/guides/json-to-pdf.md)

### Does it render to Excel?

It can — `@quario/xlsx` renders any definition — but a certificate is a page, not a grid. The
module table lands as real cells. The headline and the signature lines land as text rows above and
below it. Use the workbook for the register of who holds a certificate, not for the certificate
itself.

Word is the exception among the non-PDF targets. A certificate is a page, and `@quario/docx` is a
page-shaped target, so the landscape geometry and the signature lines survive. The recipient can
also sign or amend it. [Word documents →](https://getquario.com/guides/docx-template.md)

### Can I use this certificate template commercially?

The definition is yours — the report definitions, data, and output you create with quario belong to
you. quario is free to evaluate with no time limit. Issuing certificates to real people is past
evaluation, so that needs a license for each production deployment. Its users, agents, and renders
are never counted. [Pricing →](https://getquario.com/pricing.md)

### Can one definition cover every holder?

Yes. The definition is the certificate. Each render is one data document. A second holder is
another JSON file, not another report.

### Where are the other templates?

[Browse the template gallery →](https://getquario.com/templates.md) — summary reports, payslips, invoices, and more.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://getquario.com/"},{"@type":"ListItem","position":2,"name":"Templates","item":"https://getquario.com/templates"},{"@type":"ListItem","position":3,"name":"Certificate","item":"https://getquario.com/templates/certificate"}]}
```
