How we built the feedback widget

We at Portabella recently released Portabella Feedback, it's a customisable, end-to-end encrypted feedback widget you can drop into your site in seconds. It's one of the first integrations built on top of Portabella via the @portabella/sdk, however it does live within Portabella itself, we decided not to spin it out as its own product (as we did with PrivaNote).

If you're wanting a closer look at exactly what Portabella Feedback is, we have a landing page at where you can see what it looks like and a little marketing material about it.

This tutorial is going to provide more information around how it works and how we built it.


Portabella Feedback is a Preact widget distributed via our CDN. We allow injecting variables when you include the script into you page. As we mentioned above it leverages the @portabella/sdk to handle end-to-end encrypted data storage.

To include the widget on your site you'll need to include a code snippet that looks similar to this:


Creating a Preact Widget#

Rendering a Preact application on a DOM node is very simple, we didn't use any fancy frameworks to enable this to happen. At it's core, to render a simple "Hello World" component it looks like the following

import { h, render } from "preact";
const element = document.getElementById("<ELEMENT_ID>");
render(<div>Hello World</div>, element);

Everything else is just sugar on top of this concept.

Injecting styles#

You can of course override the Widget styles manually by including CSS files, however for a no-code type approach we allow customising the widget in a nice GUI.

This process modifies the end script we ask users to include on their site. What we mean by modifying is adding data-pf-* tags to the resulting script so that we can grab those in our Preact component and update properties.

For example changingthe primary color of the widget looks like this from the script side


and in our Preact component we can leverage inline styles to apply that new color:

const primaryColor = element.getAttribute(`data-pf-primary-color`);
return (
<div style={{backgroundColor: primaryColor}}>...</div>

Saving feedback#

The final piece of the puzzle now that we have a configurable widget users can included on their page is actually saving feedback to Portabella.

That process is only a few lines of code and looks as follows:

async function submitFeedback ({ from, message, rating }) {
const { Project } = await import("@portabella/sdk");
const sdk = new Project(token, projectId);
await sdk.fetchPublicKey();
await sdk.addCard({
title: "New Feedback submission",
description: `
Rating: ${rating}
${from && `Submitted by: ${from}`}

We do this trick of importing the @portabella/sdk on submission as it's a little heavy, and don't want to slow down users who don't interact with the widget. Doing it this way keeps the initial bundle to only a few kB downloaded.

After clicking submit (and a quick loading animation) your user feedback is on it's way to your Portabella project. End-to-end encryption has never been easier!