8

 MIN READ

How We Built a Pure Canva-Like Drag Drop in Poper

Hey there! I'm Pratik, CTO at Poper, and today I'm super excited to share how we transformed our popup / widget builder into a fully customizable canvas with Canva-like drag-and-drop functionality. Trust me, it wasn't as straightforward as we initially thought! 🎨

The Starting Point: Why We Needed This

When we first launched Poper, we had these nice-looking but pretty rigid templates. Don't get me wrong – they looked great, but they were like those fancy restaurants where you can't modify your order. Want to add a background box? Sorry, that was not possible at all!

Old Poper with little customization

As design enthusiasts ourselves, this limitation was driving us nuts. I mean, if you're creating a popup for your website, you'd want it to match your brand perfectly, right?

New template

I mean, just look at the above template; it's almost impossible to create it using a rigid template system.

Browse new Templates here

Market Research: What Others Were Doing

Before jumping into development, we did our homework and checked out other popup builders. Honestly? We were pretty disappointed. Most of them had the same limitations we were trying to break free from.

There was only one competitor (can't take the name) with pure drag-and-drop functionality, but the UX felt like trying to solve a Rubik's cube blindfolded – it was all over the place and nowhere near as smooth as Canva.

The Initial Challenge: "How Hard Could It Be?"

Using package for drag drop

Our first thought was pretty naive: "Let's just find a React library and plug it in!" Oh boy, were we in for a surprise. We quickly discovered two major challenges that made our case unique.

1. The Canvas Dimension

The first major hurdle we faced was fundamentally different from what Canva deals with. In Canva's world, they mostly work with fixed canvas dimensions – you know exactly how big your Instagram post or presentation slide will be. But in our case? It was like trying to paint on a canvas that keeps changing size.

We had to handle cases where users wanted full-screen popups with 100% width, or popups that dynamically adjusted based on content. Imagine trying to place a button exactly 20px from the center of a popup when canvas dimensions keeps moving around! We needed a system that could handle these cases.

2. The Coordinate System

The second challenge was even trickier. Traditional canvas implementations, including Canva, use what we call a top-left coordinate system. Think of it like a graph where (0,0) is at the top-left corner, and everything is positioned relative to that point. This works great for fixed-size canvases, but for us? It was like trying to build a house on quicksand.

Here's why: Let's say a user places an element at 200px from the left on a 1920px wide screen. Looks perfect! But what happens when someone views that same popup on a 1440px screen? Or a 4K display? That element would appear in completely different relative positions. We needed something more robust.

Poper coordinate system

After much deliberation, we made a decision that initially seemed crazy but turned out to be brilliant: we moved our coordinate system's origin to the center of the canvas. Think of it like having (0,0) right in the middle of your popup. This meant that elements could be positioned relative to the center, making them much more consistent across different screen sizes.

Building the Foundation

After realizing no existing npm package would perfectly fit our needs, we had to get creative. We couldn't just override our existing rendering engine – we needed to enhance it. We created a custom draggable layer that sits on top of our existing system.

This wasn't just about slapping a drag-and-drop feature on top of our existing code. We had to carefully consider how this new layer would interact with our existing positioning system. We spent hours fine-tuning the CSS positioning calculations to ensure that when you dragged an element, its final position would be exactly where you expected it to be, regardless of the canvas size or screen dimensions.

The "Wait, We're Not Done Yet" Moment

Version 1 of Poper Drag and Drop

Just when we thought we'd nailed it (at this point we launched on AppSumo! 🎉), reality hit us hard. Users started creating more complex designs, and we discovered several crucial features were missing.

The Z-Index Issue

Outline going behind

The first issue we encountered was with element outlines. We had implemented a simple hover effect that added an outline to elements when you moused over them – pretty standard stuff, right? Wrong.

Solution -

Create what we call a "pseudo layer" – essentially a ghost copy of our canvas that lives above the actual content. This layer doesn't contain the actual elements but instead handles all our interactive features like outlines and hover states.

Outline fixed for drag drop

Resizers

Next up was the resizing challenge. Initially, users could only resize elements through our settings sidebar, entering exact pixel values. This was definitely not fun.

Solution - 

We turned back to "react-draggable". We created custom resize handles that would appear as part of our pseudo layer. These handles needed to be smart – maintain aspect ratios when needed, and update both the pseudo layer and the main rendering layer simultaneously.

Resize the image with resizers

Users could now just drag and resize directly on the canvas, making the whole experience much more intuitive.

Snapping

We wanted elements to naturally align with each other, but this isn't as simple as just checking if two elements are close to each other. We had to create a comprehensive system that understood different types of alignment – edges, and centers.

Snapping elements in Poper

Solution -

Precalculate what we call "snap points" for all static elements before a drag operation begins. These snap points include edges, centers, and other significant positions. As you drag an element, we continuously check its position against these snap points. When it gets close enough to a snap point, we swap the drag position with the snap point, pulling the element into perfect alignment.

But the real challenge was making this look good. Those dashed guide lines you see when elements align? They're actually dynamically calculated based on the maximum and minimum positions of all involved elements. We have to constantly update these calculations as you drag, ensuring the guidelines appear smooth and natural.

Zoom Feature

Finally, we tackled zooming. Using "react-zoom-pan-pinch" seemed straightforward at first, but we quickly hit a wall. We were using iframes to isolate our canvas CSS (especially for handling different device previews), but this made gesture handling a nightmare. Mouse and gesture events weren't propagating correctly from the iframe to the main window.

After seeing that even Canva doesn't use iframes for their canvas, we made the bold decision to remove them entirely. This solved our zoom issues but created a new problem: how would we handle responsive previews? Our entire system relied on media queries in these iframes to show different device views.

The solution came in the form of container queries – a relatively new CSS feature. We rewrote our responsive logic to use container queries in the editor, while keeping media queries for the actual rendered popups. This gave us the best of both worlds: smooth zooming and panning in the editor, with proper responsive behavior in production.

So, The Tech Stack? 🛠️

Surprisingly minimal:

  • react-draggable

  • react-zoom-pan-pinch

  • A lot of coffee ☕

We also wrote a migration script to help users transition their existing campaigns to the new system.

The Results

The response has been absolutely incredible. Users who were previously limited to basic templates are now creating sophisticated, branded popups that look exactly how they want them to.

Our internal team of template creators have more freedom than ever.

What's Next?

While we're not trying to become Canva (we're popup, widgets builders at heart! 💪), this upgrade has opened up endless possibilities for our users. They can now create any kind of popup or widget they can imagine, and that's exactly what we wanted.

Remember, good popups aren't just about fancy design – they're about creating effective marketing campaigns that help grow your business. But now, they can look pretty darn good while doing it!

Enjoyed reading it? Spread the word


© 2024 Poper (Latracal). All rights reserved.

Grigora Made with Grigora