Thanks are in order to Zeina, Kathy, Andy, Josh, and more who helped me get past stuckness and achieve a very impactful solution with Salesforce, Flow, and UnofficialSF.

During the past few months, I’ve been on a journey to make the perfect form. The “PERFECT” form??? you may wonder? Well, of course perfect is in the eye of the beholder and it’s an unattainable state anyway (my therapist likes to remind me). Let me explain more about what perfect forms means to me.

A form has two basic components:

  1. Display a question
  2. Display answer box (could be multiple choice or free response)

Ok, this is an over simplification. Of course, there’s the browser functionality, the background and general page design, usable font, buttons for “back,” “next,” and “submit,” mapping fields, prefilling with existing data… there may be conditional logic, redirects, success messages, validation, and much, much more. But for starters, I had very specific requirements for the two, plain, vanilla components of a form.

Question text needed to show up in what we call “Rich Text.” Meaning, ability to show text with bold, italics, colors, bullets, line breaks, hyperlinks, all of the text editing features that we know and love. The questions on my form were not simple like “First Name” “Last Name.” They were complicated like,

"Explain the relationships between you and your community partners.  In your answer, be sure to cover x, y, z (bullet points).  Also, refer to this (link) for a definition of what we mean by community partner in this context."

And further more, we wanted the ANSWER box to also have Rich Text capabilities. However, in Salesforce, there is a tradeoff between Rich Text fields and displaying a character counter. Plain text fields automatically show a little tally of the number of characters used compared to the character limit for the field. Rich Text fields don’t. So, you gain formatting complexity but you lose warnings for approaching the character limit for the field. This tradeoff was messy for us, and we didn’t want to choose one or the other.

So, how did we make this happen with Salesforce Screen Flows? Well, the answer is a lot of sweat and tears, collaboration, networking, and ultimately, a success story. Let’s dive in and show you how it all works!

Unofficial SF – open source treasure trove

Those of you who have been following the blog for awhile know that I love to contribute to Open Source projects, and leverage open source solutions as much as possible. So, I was delighted to use uSF components in my form building, with guidance from a more seasoned form builder at a consulting firm.

The component Text Area Plus! should solve all of our problems! It contains a character counter and rich text capabilities for the answer text, and it contains a “custom label” attribute to enter the question text.

The only problem was that the “custom label” attribute didn’t (yet) support rich text rendering when I first got my hands on the component AND the character counter feature came paired with the “find and replace text” feature that was extraneous for our purposes.

So, what’s an admin to do?

Troubleshooting and Triumph

First, I tried to fix the problem on my own. I figured if the custom label attribute didn’t allow for rich text for the question text, then I would just use the standard Display Text component in the Flow Builder interface. However, I quickly struck out because using two components for each question-answer pair rendered with an unseemly buffer space, and caused UX confusion. I was disappointed by this, but too stubborn to stop here.

This picture is from BEFORE the solution got worked out! Custom Headers are a different uSF component that I do not cover in this post.

Next, I asked some experts for advice. One very helpful colleague directed me to this resource on using Text Template variables to store text with Rich Text tags, and then populate standard component labels with the variable, such that the label will render with rich text. Seems like a great idea, but unfortunately, it doesn’t work for all standard components (like Lookup) and also, it didn’t work with the custom component that I had installed from uSF.

Not one to give up quickly, I reached out to a friendly Flow expert next! He was generous with his time but we quickly came to the conclusion that my problem was developer related, not Flow related. Flow on it’s own couldn’t do the thing that I wanted it to do SO badly! But then we had a breakthrough. My friend was friends with the developers working on the Text Area Plus! component, and he immediately made a Slack intro between us, which kicked off a fantastic collaboration.

Through a series of Looms and Zooms (lol), I was able to convey what I needed the Flow component to do, and validate that my problems were not merely a mistake on my part.

  1. I needed the Label attribute to read and render Rich Text stored in a Text Template variable
  2. I needed the character counter to display separately from the Find and Replace feature. They should have been separated already, but there was a bug that displayed them together.

If we could get these two issues resolved, then I would be well on my way to Form-building-bliss.

To my amazement, my new friend who contributes his time to uSF came out with a new version of Text Area Plus! within a few weeks that addressed all of my concerns. I am SO delighted with the outcome and so excited to help more people be able to accomplish their form building dreams “on platform” rather than default to third party form building platforms that integrate with Salesforce.

Try this at home!

So, here’s my super duper form building tips for Rich Text enabled forms in Salesforce (screen) Flow.

  • Install the latest version of Text Area Plus! (Please make sure to do your testing and building in a Sandbox)
  • In Flow, create a Text Variable called recordId. Then, use this variable to “Lookup” the record that you are updating. In this case, I am updating an Opportunity record [in my org, we call Opportunities, Requests].
  • In Flow, follow instructions here to build out the text for the Questions you wish to include in your form. I suggest that you name each Variable with a naming convention such as Q_FullName. The Q_ reminds me that this text is a question that will be displayed with an answer box.
  • OPTIONAL: If your form needs to display text that is already stored in Salesforce for some answers, OR if your form will be filled out and subsequently revised (so you want to prefill with prior answers), you need to have a variable to store the field value for the answer to each question. So, in my example, that would look like a variable called A_FullName that corresponds with Q_FullName. You will pull in the field value by querying the record in the Get Record element from earlier in the Flow. You will need one of these for each question/answer pair.
  • OPTIONAL: In Flow, create a Formula. I named mine isViewable. I am going to make some hidden display components next, which will make maintaining my form MUCH easier. This part is optional!
  • OPTIONAL: In Flow, drag and drop a Screen Element in your Flow Builder canvas. Then, drag a bunch of Display Text components from the standard Component menu. You can name these components D_xyz to indicate that they are for Display. Leave yourself a note about what question will appear below the Display Text. Then, make the Display Text conditionally visible by going to the Set Component Visibility menu and referencing the isViewable formula that we made in the prior step. These will not show up in “published” mode but you will always see them in Edit mode.
  • Now, you should have a Flow Screen that has a bunch of Display Text (one for each question), all of which have Component Visibility set to be hidden. The reason why I like to do this is because there is no visual indication of which Text Area Plus! component corresponds to which question. So these are little visual hints that I leave like breadcrumbs for future me to benefit from. Let’s be honest, these forms are eventually going to need question revisions and it saves a LOT of time to know which question is which without having to click into each component.
  • Ok, now… finally… we are ready to add Text Area Plus! components. Drag one below your first (invisible) display text. You will want to give this a good name. I like to say, TAP_FullName. So now you will have a Q_[xyz] and a corresponding TAP_[xyz] element for each question in your form. Optionally, you may also have A_[xyz} and D_[xyz].
  • There are several attributes that you need to populate in Text Area Plus!
    • API name = [up to you… I use the naming convention TAP_[xyz]
    • Text mode = Rich Text
    • Component Label = [select appropriate Question variable stored in the Flow canvas]
    • Initial Text value (aka Prefill) = [Optional – select appropriate Answer variable stored in the Flow canvas]
    • Character Counter = checked
    • Maximum character allowed = [whatever you want]
    • Character Remaining Template = [I keep the default]
  • Once you have your Text Are Plus! components dragged into the Flow canvas, your form is almost built! All you need to do is connect your form to field logic in Flow and then you are ready to test.
  • Below the Screen element, add an Assignment element. This is where you will map your results from the Screen Flow into your Salesforce fields. Mine looks like this, repeated for every field. Make sure to select the appropriate TAP_xyz component and then drill down to the (dot)VALUE to map the stored text from the rich text component to the appropriate field.
  • Below the Assignment Element, add an Update Records element. This is the element that will *actually* replace fields in Salesforce with the new fields from the form. Mine is very simple:
  • How you finish your Flow is up to you. You can have a “Success” screen, you can add some custom buttons, or you can just end it right here! I won’t cover these options in this post.

The whole flow ends up being quite short (only 4 elements!) but LOTS of variables and components mixed in.

Man, this seems like a lot of work, right? Let’s review the high level steps:

  • Store the Record Id in a variable for the record that kicks off your Flow (this is the record that the Flow will prefill from and will eventually update) and use the Record Id to look up the full record.
  • Create a Text Template variable for each question
  • OPTIONAL: Create a Text variable for each answer (if you are using prefill)
  • OPTIONAL: Create a Display Text component for each question (useful if you have a lot of questions). If you are using this method, create a Formula that will control component visibility.
  • In the Flow Screen, drag a Text Area Plus! component for each question
  • In the Text Area Plus! component, map the Question and Answer fields based on your previously created variables
  • In an Assignment element, map each value from Text Area Plus! to the corresponding field in Salesforce
  • In an Update Records element, update your record(s) in Salesforce to save your end user’s work and “submit” the data into Salesforce


As you can see in the image below, we got everything we were hoping for with this solution: Rich Text question text (I highlighted indentations, hyperlinks, bold, etc), Rich Text answer section (redacted for privacy), and a Character Counter (this example is over the limit!).

It’s a beast to set up, but if you carefully follow the steps in this blog post, I believe that you can do it! Feel free to reach out with any questions, I am totally happy to cheer you on!

I feel very inspired knowing that I can recruit a “tiger team” of generous, patient, open-source community members to help me solve difficult issues that I can’t tackle on my own. I think that matters even more than building forms!

6 thoughts on “Rendering Salesforce Flow-based forms with Rich Text: an open source collaboration triumph

  1. I love your tip about adding “not viewable” Display Texts to the screen to identify what some of the components are! Maybe someday Salesforce will give us developers a way to add our own Previews to our custom components.

Leave a Reply