Paperclip Basics

You can think of Paperclip as a language that focuses purely on your web application's appearance - just covering HTML, CSS, and basic components. With that, you can construct almost all of your application UI in Paperclip. For example, here's a simple list:

main.pc
โšก๏ธ Preview

The <!-- Preview --> section isn't actually production code - it's used primarily for development, and visual regression testing purposes. It's an important part of Paperclip's design, so you'll be missing out a whole lot if you don't create previews. More on that in a sec.

Here's how you can use the template above in a React app:

import * as React from "react";
import * as styles from "./GroceryList.pc";
export function GroceryList() {
const groceries = [
"Milk ๐Ÿฅ›",
"Water ๐Ÿ’ง",
"Taco seasoning ๐ŸŒฎ"
];
return <styles.List>
{
groceries.map(item => (
<styles.ListItem>{item}</styles.ListItem>
))
}
</styles.List>;
}

โ˜๐Ÿป Basically, all this component is doing is adding dynamic behavior to our Paperclip building blocks, and that's all there is to it between Paperclip UIs and code, really. UIs go in Paperclip, logic goes in code. That's it. To put this into more visual terms:

JSX & PC dependency graph

This separation between UI and code actually unlocks a lot of really cool features. Namely, by isolating the UI we can optimize for very UI-specific things such as:

  • Better tooling around creating UIs: linting, realtime previews, visual editing tools.
  • Better safety with free visual regression testing.

To name a few. Really, the "separation of concerns" behind Paperclip isn't about principle, it's about function.

Let's move onto something a bit more sophisticated ๐Ÿ‘Œ. Here's a site:

HomePage.pc
Page.pc
Header.pc
Footer.pc
Tokens.pc
โšก๏ธ Preview

There are a few things going on here, but I'm just going to focus on the preview components & how this all integrates with code.

About preview components: every file has them. This makes it easy to re-use previews within other UI files to see how the entire UI shapes-up. Keep in mind that these preview components aren't intended to be used in application code - they're purely for development & testing purposes. And if you're using Webpack, Rollup, Parcel, or some other bundler, these previews will be shaken out of the application bundle, so you can add as many of them as you want without increasing your overall application size.

Testing-wise, all we need to do at this point is run the Percy CLI tool to run visual regression tests. No other setup needed.

Now onto how this integrates with code. We'll start off with the Header component since it has a few extra moving parts. Here's how it might be used in a React component:

import * as ui from "./Header.pc";
export function Header() {
return <ui.Header>
<ui.Links>
<ui.Link>Home</ui.Link>
<ui.Link href="">About</ui.Link>
<ui.Link>Contact</ui.Link>
</ui.Links>
<ui.Info title="My website" description={<>
My description
</>} />
</ui.Header>
};

Next, we'll move onto our Page component:

import * as ui from "./Page.pc";
// extension added for clarity. Usually it's omitted.
import {Header} from "./Header.tsx";
// We're assuming that Footer is already done, too
import {Footer} from "./Footer.tsx";
export function Page({ children, dark }) {
return <ui.Page dark={dark}>
<Header />
<ui.Content>{children}</ui.Content>
<Footer />
</ui.Page>;
}

Can you see the pattern here? The structure & dependengy graph of our JSX components are just about the same as the PC components. If we're looking at the PC graph:

JSX & PC dependency graph

Our JSX graph looks very similar:

JSX & PC dependency graph

The similarities makes sense since both PC and JSX files represent the same UI, they're going naturally fall into similar structures. For the most part, an entire application can be written like this. There will be a few cases that Paperclip can't handle of course, but the language is unopinionated enough to get out of your way when you want it to, so you can easily handle those edge cases.