guideExport to PDF

The ExportPdf feature allows you to generate a PDF file directly from the CKEditor 5 WYSIWYG editor content.

When enabled, this feature sends the content of your editor together with the styles that are used to display it to the CKEditor Cloud Services HTML to PDF converter service. The service then generates a PDF document that can be downloaded by the user. This allows you to easily print your content to the PDF format.

This is a premium feature. Please contact us if you would like to purchase a license. Let us know if you have any feedback or questions!

You can also sign up for the CKEditor Premium Features 30-day free trial.

If this feature is used without authentication, the resulting document will be watermarked.

The complementary pagination feature allows you to see where page breaks would be after the document is exported to PDF. Thanks to the live preview, the user is able to fine-tune the structure of the output document when editing it. In addition to this, the pagination feature shows you the page count and allows to easily navigate between the document pages.

# Demo

The demo below allows you to generate a PDF file based on the editor content. Craft the document content in the WYSIWYG editor, then click the “Export to PDF” toolbar button Export to PDF to save it as PDF.

The Flavorful Tuscany Meetup

Welcome letter

Dear Guest,

We are delighted to welcome you to the annual Flavorful Tuscany Meetup and hope you will enjoy the programme as well as your stay at the Bilancino Hotel.

Please find attached the full schedule of the event.

The annual Flavorful Tuscany meetups are always a culinary discovery. You get the best of Tuscan flavors during an intense one-day stay at one of the top hotels of the region. All the sessions are lead by top chefs passionate about their profession. I would certainly recommend to save the date in your calendar for this one!

Angelina Calvino, food journalist

Please arrive at the Bilancino Hotel reception desk at least half an hour earlier to make sure that the registration process goes as smoothly as possible.

We look forward to welcoming you to the event.

Victoria Valc signature

Victoria Valc

Event Manager
Bilancino Hotel

 

 

 

The Flavorful Tuscany Meetup Schedule

Saturday, July 14
9:30 AM - 11:30 AM

Americano vs. Brewed - “know your coffee” with: 

  • Giulia Bianchi
  • Stefano Garau
  • Giuseppe Russo
1:00 PM - 3:00 PM

Pappardelle al pomodoro - live cooking

Incorporate the freshest ingredients 
with Rita Fresco

5:00 PM - 8:00 PM Tuscan vineyards at a glance - wine-tasting 
with Frederico Riscoli

 

# How it works

The PDF export feature collects the HTML generated with the editor.getData() method and the default editor content styles combined with the styles provided by you in the configuration. It then sends them to the CKEditor Cloud Services HTML to PDF converter service. The service generates a PDF file and returns it to the user’s browser so they can save it in the PDF format on their disk.

The crucial aspect of this feature is its configuration. In order to ensure that the generated PDF looks as close as possible to the same content when it is displayed in the WYSIWYG editor, the feature must be carefully configured.

  • The complementary pagination feature provides live preview of the document’s page breaks, ensuring the output document looks correct.
  • If you would like to export your content to an editable format, using the export to Word feature will allow you to generate .docx files out of your editor-created content.
  • If you would like to use the track changes feature and show suggestion highlights in the PDF, refer to the Saving data with suggestion highlights section.

# Before you start

This is a premium feature and you can purchase a license here or contact us for a tailor-made offer. Export to PDF then needs to be configured to run without the watermark.

After you purchase a license, follow the steps below, as explained in the {@link @cs guides/export-to-pdf/quick-start Export to PDF quick start guide}:

  • {@link @cs guides/export-to-pdf/quick-start#log-in-to-the-ckeditor-ecosystem-dashboard Log into the CKEditor Ecosystem customer dashboard}.
  • {@link @cs guides/export-to-pdf/quick-start#creating-token-endpoint Create the token endpoint needed for authorization}.
  • Install and configure the CKEditor 5 export to PDF plugin.

# Installation

To add the export to PDF feature to your editor, install the @ckeditor/ckeditor5-export-pdf package:

npm install --save @ckeditor/ckeditor5-export-pdf

Then add the ExportPdf plugin to your plugin list and configure it:

import ExportPdf from '@ckeditor/ckeditor5-export-pdf/src/exportpdf';

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [ ExportPdf, ... ],
        toolbar: [
            'exportPdf', '|',
            ...
        ],
        exportPdf: {
            tokenUrl: 'https://example.com/cs-token-endpoint',
            stylesheets: [
                './path/to/fonts.css',
                'EDITOR_STYLES',
                './path/to/style.css'
            ],
            fileName: 'my-file.pdf',
            converterOptions: {
                format: 'A4',
                margin_top: '20mm',
                margin_bottom: '20mm',
                margin_right: '12mm',
                margin_left: '12mm',
                page_orientation: 'portrait'
            }
        }
    } )
    .then( ... )
    .catch( ... );

Read more about installing plugins.

# Configuration

For more technical details, please check the plugin configuration API.

The configuration is the key to allow the HTML to PDF converter service to generate PDF documents that look as close as possible to the content created in the rich-text editor.

The configuration consists of 3 main parts:

  • The converter options that tell the HTML to PDF converter service what is the format of the page (A4, Letter), the page orientation, etc.
  • The stylesheets that should be sent to the service. They allow styling the content in the PDF document with the same styles that are applied to the content in the editor.
  • The content styles used in the editor when it is rendered on the page.

These options need to stay in sync. For example:

  • The stylesheets sent to the service must define the same typography that is used in the editor.
  • The editor’s content container should be styled in a way that it reflects the page size and margins defined in the converter options.
  • All web fonts defined on the page where the editor is used must be sent to the service as well.

Read on to learn how to achieve this.

# Default configuration

This is the default configuration of the PDF export feature for CKEditor 5.

{
    exportPdf: {
        stylesheets: [ 'EDITOR_STYLES' ],
        fileName: 'document.pdf',
        converterUrl: 'https://pdf-converter.cke-cs.com/v1/convert',
        converterOptions: {
            format: 'A4',
            margin_top: '0mm',
            margin_bottom: '0mm',
            margin_right: '0mm',
            margin_left: '0mm',
            page_orientation: 'portrait',
            header_html: undefined,
            footer_html: undefined,
            header_and_footer_css: undefined,
            wait_for_network: true,
            wait_time: 0
        },
        dataCallback: ( editor ) => editor.getData()
    }
}

# Plugin options

For some use cases the default configuration will suffice. As you can see in the example above, you can improve how your PDF file will look by adjusting the PDF export plugin configuration.

  • config.exportPdf.stylesheets

    You can set the paths (relative or absolute URLs) to the stylesheets that should be included during the HTML to PDF conversion. If you want to extend editor’s default content styles , you have to pass a special 'EDITOR_STYLES' token before a path to your custom styling.

    Note: The order of the paths matters. If you have custom elements or have overridden some of the default editor’s content styles, the paths to your file(s) should go after the 'EDITOR_STYLES' token. See the examples in the config.exportPdf.stylesheets documentation.

  • config.exportPdf.fileName

    Sets the name for the generated PDF file (together with the extension). The default name is document.pdf.

  • config.exportPdf.converterUrl

    By default, the PDF export feature is configured to use the CKEditor Cloud Services HTML to PDF converter service to generate the PDF files. You can, however, use this option to provide the URL to an on-premises converter. Contact us if you need this feature.

  • config.exportPdf.tokenUrl

    A token URL or a token request function. This field is optional and should be used when a different tokenUrl is required for the Export to PDF feature. You can skip this option if you use the cloudServices configuration to provide the same tokenUrl (in fact in most cases you will probably want to provide the token in cloudServices, as other plugins like EasyImage or real-time collaboration will use this token as well. For the purpose of this guide, to explicitly show that this value is needed, we leave it the inside exportPdf config).

  • config.exportPdf.converterOptions

    The plugin allows you to provide a custom HTML to PDF converter configuration.

  • config.exportPdf.dataCallback

    By default, the plugin uses editor.getData() to gather the HTML to be sent to the conversion service. You can use this option to customize the editor’s data.

# HTML to PDF converter features

# Images

Currently, the plugin only supports absolute URLs as well as the Base64 format for images. See the converter documentation.

# Web fonts

If you are using web fonts via an @import or @font-face declaration, you can pass the path(s) to the .css file(s) containing them to the config.exportPdf.stylesheets. Remember that the order of the provided paths matters — stylesheets with web font declarations should be listed first. For more technical details, please check the API documentation and converter documentation.

The converter allows you to set the document’s header and footer in a similar way as you do this in your Microsoft Word or Google Docs files.

const converterOptions = {
    margin_top: '15mm',
    margin_bottom: '15mm',
    margin_right: '15mm',
    margin_left: '15mm',
    header_html: '<div class="styled">Header content</div>',
    footer_html: '<div class="styled-counter"><span class="pageNumber"></span></div>',
    header_and_footer_css: '#header, #footer { background: hsl(0, 0%, 95%); } .styled { font-weight: bold; text-align: center; } .styled-counter { font-size: 1em; color: hsl(0, 0%, 60%); }',
}

Note:

  • To ensure that the header or footer is displayed, the margin must be big enough to accommodate it. In the code above, margin_top corresponds with the header and margin_bottom — with the footer. In this example the height of both elements will equal 15mm.
  • You can set a background for the header and footer. To achieve this, use the #header or #footer selector in the header_and_footer_css option. Do not use these IDs in the header_html or footer_html options to avoid duplication. These elements are provided by the HTML to PDF converter.

As you can see in the example above, you can even set the pageNumber. But there is more — for details, refer to the converter’s documentation.

# Other

  • By default, the generated PDF file is encoded with UTF-8.
  • By default, the converter sets color-adjust: exact;. This means that your PDF document will preserve colors, images, and styles as you can see them in the editor.
  • The generated document can be watermarked. See the example and demo in the section below.

# Examples

Check out some configuration examples that will show you how to customize the export to PDF feature. In the first example, you will learn how add custom styling. The second example will show you how to set the page format. In the third one, you can see how to use web fonts in your configuration.

# Re-using custom editor styling

The default configuration of the ExportPdf plugin attaches the default editor content styles to the HTML content sent to the converter.

However, if you need, you can also set paths to additional CSS files. Let us assume that you already have a my-custom-editor-styles.css with your custom styling for the editor content that you use on your website, but you also want to include these styles in the generated PDF file.

Here is the example code:

import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
import ExportPdf from '@ckeditor/ckeditor5-export-pdf/src/exportpdf';

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [ ExportPdf, ... ],
        toolbar: [
            'exportPdf', '|',
            // ...
        ],
        exportPdf: {
            stylesheets: [
                'EDITOR_STYLES',
                // Add an external stylesheet after the 'EDITOR_STYLES' token.
                './styles/my-custom-editor-styles.css'
            ],
            fileName: 'my-document.pdf'
        }
    } )
    .then( ... )
    .catch( ... );

This is how the corresponding editor styles may look like:

/* my-custom-editor-styles.css */

/* Custom link color. */
.ck.ck-content a {
    color: purple;
}

/* Custom header styling. */
.ck.ck-content h1 {
    border-bottom: 2px solid;
}

/* Another custom styling... */
/* ... */

With these settings, the content in the generated PDF file should have the same styling as it has in the WYSIWYG editor.

Keep in mind that you are not obligated to use .ck.ck-content selectors to style your content. If your implementation contains custom CSS classes, you can use them instead.

# Setting the page format

Consistency is an important factor. To make sure that the editor content and the generated PDF file look exactly the same, you need to match their format settings. You can modify your existing stylesheet or use a new one, for example, format.css. By default the CKEditor Cloud Services HTML to PDF converter is set to A4 format, but you may change this setting in your configuration.

Assuming that you want to create a document in the US Letter format, with the standard margins (19mm for each side), here is the example code you can use:

import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
import ExportPdf from '@ckeditor/ckeditor5-export-pdf/src/exportpdf';

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [ ExportPdf, ... ],
        toolbar: [
            'exportPdf', '|',
            // ...
        ],
        exportPdf: {
            stylesheets: [
                'EDITOR_STYLES',
                // Add an external stylesheet after the 'EDITOR_STYLES' token.
                './styles/format.css'
            ],
            fileName: 'my-document.pdf',
            converterOptions: {
                // Document format settings with proper margins.
                format: 'Letter',
                margin_top: '19mm',
                margin_bottom: '19mm',
                margin_right: '19mm',
                margin_left: '19mm',
                page_orientation: 'portrait'
            }
        }
    } )
    .then( ... )
    .catch( ... );

This example focuses only on preparing the editable to match the converter settings. Please keep in mind that as a result, the appearance of your editor may change. Depending on your editor type and implementation or even some inherited global styles like box-sizing, applying new padding values may change the size of the editor on your website.

For the purpose of this example, box-sizing: border-box was implemented to make sure that the editor’s width will not change.

Now set the corresponding editor styles:

/* format.css */

/* Styles for the editable. */
.ck.ck-content.ck-editor__editable {
    /* US Letter size. */
    width: 215.9mm;
    /* Padding is your document's margin. */
    padding: 19mm;
    /* You don't want to change the size of the editor by applying the new padding values. */
    box-sizing: border-box;
    /* ... */
}

With these settings, the content in the generated PDF file should have the same US Letter format layout as it has in the editor.

# Providing web font styles

This time you want to add a web font to your plugin. Let us assume that the editor is used on a page with a certain typography, so the content in the editor inherits the font styles from the page. As such, these styles need to be passed to the HTML to PDF converter service.

The example below uses a web font from the Google Fonts service. For your convenience, the @import declaration and any font styles needed for your website are kept in the separate file, for example: fonts.css.

/* fonts.css */

@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;700&display=swap');

html, body {
    font-family: "Source Sans Pro", sans-serif;
    /* ... */
}

/* ... */

This allows you to use the web font settings in the plugin, without any additional tweaks. Just pass the path to the file in the config.exportPdf.stylesheets configuration option.

It is important to remember that the order matters here. Font declarations should be at the very beginning of the stylesheets’ array, otherwise there is no guarantee that the font styling will be applied to the PDF file. Refer to the config.exportPdf.stylesheets API documentation for more details.

import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
import ExportPdf from '@ckeditor/ckeditor5-export-pdf/src/exportpdf';

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [ ExportPdf, ... ],
        toolbar: [
            'exportPdf', '|',
            ...
        ],
        exportPdf: {
            stylesheets: [
                // Add the external stylesheet before the 'EDITOR_STYLES' token.
                './styles/fonts.css',
                'EDITOR_STYLES'
            ],
            // ...
        }
    } )
    .then( ... )
    .catch( ... );

Thanks to this, the editor inherits the font settings and you can be sure that they will be applied in the generated PDF file as well.

Take a look at another example of a fonts.css file. Suppose that your website uses the Source Sans Pro font as before but this time you want the Inter font to be used in the WYSIWYG editor. So the file should look like this:

/* fonts.css */

/* Import the web font for your website. */
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;700&display=swap');
/* Import the web font for your editor. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');

/* Use the Source Sans Pro web font in your website. */
html, body {
    font-family: "Source Sans Pro", sans-serif;
    /* ... */
}

/* Use the Inter web font in your editor. */
.ck.ck-content.ck-editor__editable {
    font-family: "Inter", sans-serif;
    /* ... */
}

/* ... */

Having the file set like this for your website and just re-using it in config.exportPdf.stylesheets makes the whole setup as simple as possible.

# Adding a watermark to the document

Apart from adding a header and a footer, there is also the possibility of adding a watermark to the generated document. This can be achieved by utilising config.exportPdf.dataCallback.

To do this, you need to get the data that is being sent to the converter first and update it with a watermark markup:

exportPdf: {
    ...
    dataCallback: ( editor ) => {
        return `
            ${ editor.getData() }
            <div class="watermark">Draft document</div>
        `;
    },
    ...
}

Then update the custom CSS file with the proper styles:

.watermark {
    font-size: 50px;
    opacity: 0.5;
    color: black;
    position: fixed;
    left: 20%;
    top: 50%;
    transform: rotate(25deg);
    letter-spacing: 10px
}

Below you can see a simplified demo with the final result. Click on the Export to PDF toolbar button to generate the document with a watermark.

The purpose of writing

In the days of images and icons, the written word has significantly lost its impact. The potential readers rush and suffer attention deficiency, hence all writing longer than a glance is often omitted. This is a hard situation for anyone writing anything other than a novel, as this invalidates the main purpose of writing anything at all.

And the main purpose of writing is to sell. Whatever you do, this is always about selling. Not only writing, but anything is about selling. Adverts sell. TV commercials sell. Facebook posts sell. Tweets sell. This may be a product, a service, a car, a software bundle, but also your point of view, your opinion, your image. Even your cosplay photos on Instagram sell some ideas about yourself.

This is even more so in the professional writing environment, as none of us doubts this — we are here to sell. Whether we want to encourage people to try the new fancy frapuccinate grande turtleneck soda, convince them to exchange their old 2015 kombi van model for the newest hybrid 2020 model, or if we want them to buy a book about the Silesian private eye — we all aim at selling. Money does not need to be involved. The readers' attention should be perceived as a modern currency. Their time, likes, retweets, and recommendations pose a value that should not be overlooked.

To gain, we need to draw their attention. But to draw the attention of the recipient, we need to reach them.

The hegemony of SEO

In the cluttered trash can that the internet has become over the past two and a half decades gaining the attention of the potential client is a task best described as desperate. User-generated content competes with big companies' output in the struggle for reach. Paid content attacks the strongholds of native exposure, racing to hook up into the latest trends in the short term while trying to stand relevant in the long term.

Searchability and indexability is the 20th-century golden calf, pursued by all those who want to sell. If you cannot or do not want to afford some large (and by large I do mean mammoth sometimes) spendings on delivering your content where you want it, you need to rely on the unclear, shape-shifting changes of the recent Google algorithm update that may help you drift to the very first page of the search results for insanely specific keywords. Right into the middle of the page, just below the paid results.

This is one mundane task and may seem futile at times, but if you work hard, follow all the current requirements, abide by all the rules and keep your head over the water for long enough, then you may achieve the goal and be a relevant answer for a question once asked. This is good. I mean, what is good, is that there are, after all, some rules, that can be followed to gain exposure and recognizability. Whimsical and unstable as they may be, they are there to help the big search engines streamline their results to earn more. After all — selling is the ultimate goal, isn’t it?

There is an old saying, that good content will always eventually sell, but the “eventually” part is the problem. There are, of course, cases, when incidental produce will float to the top and hit hard. It is every marketer’s wet dream, to hit big, go viral, and gain reach undreamt of before. Some of us, content producers, online writers, try to aim for the top, but most realize that the higher you aim, the harder you fall. And then the countless faceless minions feeding the World Wide Web would rather settle for a scrupulous and meticulous attempt at following the rules grasping at the fleeting hope of being relevant.

Not abiding by the rules — whatever they might be this morning — is a scary, unknown land that tends to be avoided at all costs.

The deterioration of the substance

Written content at present struggles with two, mostly mutually exclusive notions. One is the need to convey a message and grasp the readers’, users’ attention for this short period they are willing to sacrifice between their own selling attempts. The other is the burning coercion of being accountable, searchable, indexable, and Google oriented.

Content is produced to satisfy the digital, ephemeral taste of algorithms, to try and aim at the hardly predictable liking of AI-driven mainframes that nobody knows and nobody fully understands. Things were set in motion that can not be stopped. Recent research shows that people do not understand how and why the content is fed to them. What are the criteria that cause the choices the machines made? These elude us. And — quite frankly — hardly anybody has neither the time nor the alacrity to ponder on that in between selling and buying, in the midst of insane, initiated consumption of goods, ideas, and concepts aimed at self-fulfillment.

And nobody cares for the content delivered to them even though so much hard work, planning, and rehearsing of researched digital approaches were employed and invested into its creation.

This is because the content was created to satisfy the electronic collective mind of vast computing systems, digesting the data that they can process and excreting anything that deviates from the blurry guidelines confining the usefulness and desirability of those behemoth electric constructs.

The content we produce is not aimed at humans.

# Known issues

Not all CKEditor 5 plugins and features are compatible with export to PDF at the moment. Here is a list of known issues:

  • Media embed – Not supported.
  • MathType – Not fully supported yet. Right now the plugin parses the data but not the formatting. Feel free to contact us if you are interested in this feature.

# Common API

The ExportPdf plugin registers:

  • The 'exportPdf' button.

  • The 'exportPdf' command implemented by ExportPdfCommand.

    The command can be executed using the editor.execute() method. However, should the command be used directly (not via the toolbar button), the options need to be specified or gathered from the config. Otherwise the command will not execute properly.

    And example code to use the command directly should look like this:

    // Start generating a PDF file based on the editor content and plugin configuration.
    const config = editor.config.get( 'exportPdf' );
    editor.execute( 'exportPdf', config );