A template engine that comes with tools for building presentational components in realtime
paperclip
Build UIs at the speed of thought. Paperclip is a template engine that comes with tools for building presentational components in realtime, all within your existing IDE:
This took me about 12 minutes to make start to finish.
Features
- Templates compile down to plain React code (more targets planned).
- Scoped CSS. Write styles however you want, without worying about them leaking out.
- Percy integration for catching visual regressions.
- Compatible with existing CSS libraries like Tailwind, Bulma, and Bootstrap.
Resources
- Slack channel - for questions, feedback, help, or whatever!
- Installation
- Project installation - Basic installation of Paperclip for new and existing projects.
- VSCode Extension - Getting started with the VS Code extension.
- Webpack setup - Setting up with Webpack
- Documentation
- Syntax - How to write Paperclip documents
- React usage - Using Paperclip UIs in your React code
Example
Here's what Paperclip's syntax looks like (from GIF above):
<!-- @frame is like a doc-comment & attaches metadata about your elements for the designer & other visual tooling. -->
<!--
@frame { visible: false }
-->
<h4 export component as="FormTitle">
<!-- Styles defined within elements are scoped, and don't need selectors -->
<style>
margin: 0px;
</style>
{children}
</h4>
<!--
@frame { visible: false }
-->
<!-- Note this would typically be defined in a separate file & imported into this doc -->
<input export component as="TextInput" {placeholder?} {type}>
<style>
border: 1px solid rgb(156, 156, 156);
padding: 8px 16px;
border-radius: 2px;
</style>
</input>
<!--
@frame { visible: false }
-->
<div export component as="FormFooter">
<style>
display: flex;
justify-content: flex-end;
</style>
{children}
</div>
<!--
@frame { visible: false }
-->
<!-- This typically wouldn't be defined here -->
<button export component as="Button">
<style>
--button-bg-color: rgb(116, 176, 255);
background: var(--button-bg-color);
color: rgb(46, 85, 136);
padding: 8px 16px;
border-radius: 2px;
border: 2px solid var(--button-bg-color);
</style>
{children}
</button>
<!--
@frame { visible: false }
-->
<div export component as="AuthModal">
<style>
display: grid;
grid-row-gap: 16px;
max-width: 250px;
margin: 0px auto;
/* rule of thirds */
top: 30%;
padding: 32px;
border-radius: 4px;
color: rgb(97, 97, 97);
background: rgb(238, 238, 238);
position: relative;
border: 1px solid rgb(194, 194, 194);
</style>
{children}
</div>
<!--
@frame { visible: false, title: "Auth / login", width: 586, height: 446, x: 3, y: 141 }
-->
<div export component as="Preview">
<style>
font-family: sans-serif;
height: 100vh;
</style>
{showLogin && <AuthModal>
<FormTitle>Log in</FormTitle>
<TextInput placeholder="Username" />
<TextInput placeholder="Password" />
<FormFooter>
<Button>Sign up</Button>
</FormFooter>
</AuthModal>}
{showSignup && <AuthModal>
<FormTitle>Sign up</FormTitle>
<TextInput placeholder="Full Name" />
<TextInput placeholder="Username" />
<TextInput placeholder="Password" />
<TextInput placeholder="Repeat Password" />
<FormFooter>
<Button>Sign up</Button>
</FormFooter>
</AuthModal>}
</div>
<!--
@frame { title: "Auth / Login", width: 501, height: 427, x: 0, y: 0 }
-->
<Preview showLogin />
<!--
@frame { title: "Auth / Sign Up", width: 501, height: 561, x: 581, y: 1 }
-->
<Preview showSignup />
Here's how you integrate Paperclip into your code:
import React from "react";
import * as styles from "./auth.pc";
import { TextInput } from "@design-system/components/TextInput";
import { Button } from "@design-system/components/Button";
export const LoginPage = () => {
const { onSubmit, usernameInputProps, passwordInputProps } = useLogin();
const userNameProps = useTextInput();
return <form onSubmit={onSubmit}>
<styles.Modal>
<styles.AuthModal>
<styles.FormTitle>Welcome back!</styles.FormTitle>
<TextInput type="text" {...usernameInputProps} />
<TextInput type="password" {...passwordInputProps} />
<styles.FormFooter>
<Button>Log in</Button>
</styles.FormFooter>
</styles.AuthModal>
</styles.Modal>
</form>;
};
Roadmap
What's the future looking like for Paperclip? Here's the tentative plan:
- ✅ Prettier integration
- ✅ Avocode / Figma integration (Figma to design sync)
- ? CSS & HTML linting (a11y, showing unused styles, caniuse integration)
- ? CSS tree shaking (removing unused CSS from builds)
- ? Visual builder (no-code like)
- ? Multiple compiler targets: PHP, Ruby, VueJS, Svelte
- ? IDE integrations