Show HN: Puck – Open-source visual editor for React (github.com)
I've been dipping in and out of this problem space for the last few years with many of my clients.
Puck sits somewhere between an old-school WYSIWYG-powered CMS and headless one, allowing content teams to author content using real React components.
Traditional CMS solutions were flexible but often resulted in page that completely broke the brand guidelines. Headless CMS solutions are a fantastic way of controlling brand by restricting UI changes to developers, but makes layout changes restrictive and slow as developers often need to get involved.
Puck provides a visual editor for React that can sit on top of your existing headless CMS (or act as standalone). We've been dog-fooding it on a few pages at https://measured.co and on https://wellpaid.io. So far, so good
The API is built for React, which allows FE devs to quickly integrate their existing component and add some form fields for author input, or connect it to a headless CMS of choice.
It's open-source under MIT, and pairs nicely with Next.js (check out the demo application). Next in the pipeline: support for multi-column layouts, richer demos, new plugins.
Looking forward to hearing your comments!
104 comments
[ 3.1 ms ] story [ 149 ms ] threadI plan to make it more like builder.io/demo however where CSS can be arbitrary, that way basic landing pages can be built.
Do you have any tips of things you wish you did differently, or what was more painful than you expected, as well as anything that might help in this?
A sound data model really helps things out. I'd go API-first.
Drag and drop is a PITA. Specifically multi-column layouts, which require nested dropzones and a bunch of "intuitive" UX. A good library can help here, but not do everything (we're using react-beautiful-dnd which is a bit out of date - dnd-kit might have been a better shout). This hasn't landed in our main branch yet, but you can see it under the nested-dropzones branch (https://github.com/measuredco/puck/tree/nested-dropzones).
If you could write React wrappers for your Vue components, you could potentially leverage Puck directly. That would save a lot of time. And even if not, you might be able to fork it or reuse the data model.
Happy to give you more pointers. If you want to DM, I'm @chrisvxd on Twitter/GitHub and here's my LinkedIn: https://linkedin.com/in/chrisvilla/
I really disliked the vuedraggable was handling nesting, and it's just a wrapper around a sortable. At the end of the day, my problem was simple enough that I didn't want a 500kb dependency. If you're wanting to do something like the OP but with nesting, I'd definitely start by looking at Sortable, though (maybe wrapping it the way you want).
There's not an awful lot to it.
[0] https://vuedesigner.com
> Does it allow embedding in an actual app? Thats the problem I have with these is they all require some weird form of going to their domain. I need the editor (AND the rendered page) to be 100% on my own domain. I wish they had some editor as an open source library and id just pay to have an API key or something
https://github.com/measuredco/puck/blob/cae760fbfb8497de0931...
Like on the demo where it says https://puck-editor-demo.vercel.app/edit Users Reached 20M+, I thought instead of static text, it would've shown some kind of {{template}} that shows JSON query format like `jq` does to pluck fields from arrays/objects of fetch() response bodies (how React would pass along props/state)
However you can use an adaptor if you need to pull data in via a third party API: https://github.com/measuredco/puck/tree/main/packages/adapto...
I know how to pull data in via React/JavaScript "code". If I can do that, I'm technical enough to not need a GUI to help me make a UI... do I?
Puck is targetted at content/CMS use cases, rather than general UI building. So the ability to establish guardrails in the editor experience is intentional. For best effect, we envisage Puck being used alongside a well-considered library of on-brand composable components. The aim is to enable non-developer editors/authors to freely update and build content, whilst keeping the UI consistent and on-brand.
This is a problem area we've encountered many times in our client work, hence why we wanted to scratch this itch.
Having said that, I do believe the Puck editor GUI _can_ be configured to work with remote data somewhat as you describe, using the adaptor linked above (but there's currently no demo for this feature).
However, you might be able to either wrap your component inside the `render` function and define your callback there, or use context to pass in a function from higher up the tree.
If you share your use case, I might be be able to help you out.
Looking at the comments from the dev in this thread it seems this really only supports vertically stacked layouts right now? At least the demos were responsive but each component seems to assume that it fills the width of the screen. Making responsive components in a columnar layout might be more challenging for this kind of toolset to handle.
Looking at the recipe for next.js app I noticed that the component where the page is rendered appears to be in `[...puckPath]/client.tsx` which is a "use client" component. That makes me wonder about the entire framework and whether or not it actually renders the pages on the client or the server.
If those two things are true then this might have limited application. Finding a way to handle responsive layout for columnar and/or grid based pages will be non-trivial. Finding how to mix server and client components effectively will be non-trivial.
That aside, it seems useful and decently structured. In places where we I've worked where there is a lot of customization desired, having a UI builder that customizes page layout in some data format (json or xml) has been very helpful.
There's a WIP branch with support for more sophisticated layouts here: https://github.com/measuredco/puck/tree/nested-dropzones
And I think `use client` is a Next 13 thing. Not sure of the details, but Puck definately does render server-side.
Multi-column layouts are incoming very soon
And Puck does support either server or client rendering
The data shape is detailed here: https://github.com/measuredco/puck#data
The best way to handle this is in the render function you pass to Puck, which can continue to support the old prop (`description`) and map into the new prop (`subtitle`), even if it's not provided by the author.
We don't have a system for migrating props in the actual data yet, but it's something we could look into.
I have been writing react since version 0.11 and am considering shifting to a visual for day to day development.
For a second iteration of the app, I asked ChatGPT (Plus) to help me. Gave it existing code and gave increasingly specific UI and behavior requirements. After a few hours of pair programming ... I had a working new page (with backend API integration). The UI behavior I wanted went fairly deep -- with a lot of conditional logic to render styles, handle double clicks on text to make them editable form fields, etc.
I am impressed with this approach at least for prototyping and MVPs.
The resulting page was surely not very maintainable due to the complexity of embedded logic and conditionals ... but again I wouldnt have managed to manually code such complexity myself. Maybe if forced to do it manually i would have learnt more, modularized my code more, but spend a week instead of a day achieving the result. I am not a career developer -- so for my use case I will take this productivity boost.
I think there is a great opportunity to merge a visual UI builder like this (puck) and an LLM backend/interface to radically improve productivity and make prototyping as well as building real apps (production grade, modularized, maintainable) much more easier to build.
Ex. instead of an input for the prop `name` I want a picker that fetches data from some API
Docs are limited, but there's a reference data shape here: https://github.com/measuredco/puck#adaptor
Example implementation here: https://github.com/measuredco/puck/blob/main/packages/adapto...
Example usage here: https://github.com/measuredco/puck/blob/main/apps/demo/app/c...
You can either use it for a specific prop (i.e. `name`) or spread the result of the API call across your entire component (use the magic `_data` prop).
Puck enables content teams to produce web pages using existing React components produced by their React developers in a fixed and predictable manor that keeps them within the brand guidelines.
You can’t inject arbitrary blocks and can only interact with components that are defined by your developers.
You can render fully fledged pages or even, in theory, applications.
Regarding content, Puck supports inline editing or pulling in data via an API adaptor (such as from a headless CMS).
We don’t have a rich text field type currently, but I’m not opposed to adding it. (Internally, we’ve added a markdown component to enable some basic formatting and longer form content: https://github.com/measuredco/measuredco-site/blob/02fc908b8...)
We built it because we couldn't find something that would let our clients' content teams produce content for their sites without 1) either going off-brand or 2) pestering their devs for layout changes.
In my experience, most of what content teams work with are some forms of CMS, and the design tools usually deal with layout and creating generic sites that work with the data structure inside the CMS.
[1] https://www.framer.com/developers/#overview
It's always been my dream of having something like Retool, but using your own components and completely open source. Retool is a backend layer too, so that's partially what's missing to complete the picture. But if we had that as something like a framework, we'd start getting close to the days of drag-and-drop UIs.
Plasmic is a no-code tool for building websites and applications from scratch. A great solution for a different problem.
Congrats on this release! We are actually open sourcing Plasmic soon, would love to discuss any possible ways to collaborate.
Happy to discuss/collaborate. I'm @chrisvxd on GH/Twitter, and here's my LinkedIn: https://linkedin.com/in/chrisvilla/
maybe the HN post title should mention the name of the project "Puck" for future discoverability
Have you considered integrating an LLM to expand the functionality?
Based on some recent experimentation I was able to get some fairly complex React UI and behavior out of a pair programing session ... without having a lot of React experience and skill myself. Seemed ripe with potential.