Proposify Proposal Editor, Lead Product Designer.

Rebuilding a proposal editor customers had already rejected.

45→15Minutes to prepare a quote
2.4×Higher user engagement

What I owned

  • Product strategy and MVP definition, from weekly super-user interviews
  • Editor foundation: block system, interaction model, toolbar, sections, undo/redo
  • Content reuse: variables, custom fields, template-to-proposal workflow
  • Pricing table, redesigned progressively into a real quoting surface

Constraints

  • An installed base working around the gaps, and reverting to V2
  • Four engineers, a tech lead, one PM, and the head of product
  • No rewrite available, incremental only
  • Every pattern set here would become the foundation for what came next

A thin editor doesn't fail loudly. People just quietly use the old one.

When I joined, V3 was the future of the product and barely a document editor. Text and images worked; almost nothing else did. Tables couldn't do real work and nothing let you reuse content, so customers rebuilt the same proposal by hand every time. People tried V3, hit a wall, and went back to V2, a platform that had already reached its technical limits.

The proposal editor before the rebuild: an empty white page titled About Us, a formatting toolbar across the top, and a Content panel on the right offering only four blocks: Text, Image, Video and Table.
Where it started. An empty page, a formatting toolbar, and four block types. This is what customers were trying before they went back.

Customers weren't rejecting V3. Every return to V2 was a specific, findable gap.

To find them, I ran a standing Thursday session with one to five of the editor's heaviest users, for as long as I was on the product. Every week followed the same loop:

  1. 01ListenHear the friction from the people using it hardest.
  2. 02DiagnoseWork out what is actually causing it.
  3. 03ScopeDefine the smallest version worth shipping, agreed with PM and engineering.
  4. 04ShipDesign it and get it out.
  5. ↻Re-testBack in front of the same people the following Thursday.

We phased the big capabilities instead of cutting them.

Richer block interactions and a real pricing table were first judged too large for a V3 MVP, and the concern was fair. But the interview record showed the same limitations week after week, from the same accounts, including the ones reverting to V2. That turned my opinion into a pattern with names attached.

With the PM and tech lead, I split the work into phases around one rule: build the interaction model first, so every block and feature added later would inherit it instead of becoming another special case.

Two years, in the order it was built
StartText and images
01Block system
02Toolbar & sections
03Variables & custom fields
04Pricing table
05Video, shapes, AI drafting
ThenCPQ foundation
The order matters. Each layer only became cheap to build once the one before it existed.

One interaction model for every block, and everything built on top of it.

City of Toronto | New Public Installation Space 2025
DraftSaved
Share
Overview
Scope of Work
☵ ◻
Video block, selected

+ Add block

Block Settings
Video
Full width▾
Autoplay
Block-based canvas: new block types, clearer selection and resize affordances, contextual formatting.
City of Toronto | New Public Installation Space 2025
DraftSaved
Share
Overview
☵ ◻
Aa Text$ Currencyx Multiplier$ Subtotal
Item NamePriceQtySubtotal
⋮⋮Implementation
One-time
$18,0001$18,000
⋮⋮Premium Support
Recurring, annual
$2,4001$2,400/yr
⋮⋮Onsite Training
Optional, click to add
$1,2001$1,200
After 10% discountSubtotal $18,360

Try it: toggle the optional line item

Table Settings
Pricing
Decimals: 2▾
Table footer
InteractiveOptional line items, recurring pricing, live discounted subtotal. Toggle the third row.

My first copy/paste worked for every block except the one that mattered.

It treated every block the same: copy the markup, paste the markup. That worked for text, headings and images, which is why it reached QA. But a pricing block holds live formulas and variable bindings, so a pasted copy looked identical and was quietly connected to nothing. QA caught it before customers did, and we traded the simple generic handler for per-block copy behaviour, where each block declares what duplicating it means. More work, and the version that shipped.

✕ Shipped to QA, then pulled

One generic markup handler

Block → Copy markup → Paste markup
Pricing table pastes as a lookalike: formulas gone, {{variables}} unbound, totals frozen.

Simple and general. Treats a binding as if it were decoration.

✓ Shipped

Per-block-type copy behaviour

Text → copy markup
Pricing → copy formulas + rebind

Each block type declares how it duplicates. A block isn't markup; it's a binding, and the editor had to know the difference.

The bug that changed how I think about editors. It's a data model with a UI on top.

V3 became a much more capable foundation for proposal creation.

45→15Minutes to prepare a quote
2.4×Higher user engagement

The pricing and editor architecture established here became part of the foundation for CPQ.

Next case study

Building a custom home reservation product

→