Understanding Dynamic Labels in Survey123 for ArcGIS

11-01-2018 04:54 PM
Esri Frequent Contributor
10 12 6,458

Starting with version 3.1, you can dynamically change the label of a question, using answers from other questions in the form. Dynamic question labels are particularly handy when working with very long forms, making questions in your survey more meaningful to end-users.

The Water Violation survey sample on the side, for example, shows how you can insert the Type of Violation and Name of Offender in the photo and signature questions that follow.

This is quite a simple example to illustrate the idea. As your survey includes questions across multiple groups, repeats and even pages, dynamic labels become critical to aid with form navigation and to avoid user input errors. 

The dynamic labels technique is often described in survey jargon as question piping, where user responses are inserted or piped into questions further into the survey.

You can add dynamic labels to your forms using Survey123 Connect for ArcGIS. Once published, dynamic labels will work in both the Survey123 web as well as the field apps.

The basics of dynamic labels in XLSForm

In order to insert text dynamically within a question label, you must add XLSForm variables in the label column of your survey. The syntax is quite simple. Insert ${QuestionName} exactly where you want the answer to a particular question in the survey to appear in your label.  This is what the Water Violation example illustrated above looks like in XLSForm.

You can add multiple variables to the same label but it is important to highlight that the use of full XLSForm expressions within the label column is not supported.  Survey123 will only replace XLSForm variables. For example, this is valid:

But this is not valid:

While you cannot use full XLSForm expressions within the label, you can use them in a calculate question, and then reference your calculate question in the label. Calculate questions will not show in your form, but will help you hold the output of full XLSForm expressions, so you can insert those values in a label. For example, lets pretend you want to use a dynamic label in a note to describe the total cost of repairs of a pipe, given its length:

The cost question is a calculate. It will not be shown in the form to the end-user. We use the cost calculate question to run a full expression that evaluates the total cost, and once we have that, we simply use it for our dynamic label.

Working with different data types


As you work with dynamic labels, you will notice that things are straight-forward when you want to insert values from questions of type text, decimal or integer.  All you will need to do is to reference these questions directly exactly as shown above.  When working with other types such as dates or select questions, things are a bit more complicated and you will need to pre-process user values through calculate questions before you insert them into the label.

  • Select_one questions: If you want to bring a user selection from a select_one question into a dynamic label, you have to keep in mind that by default, you are going to get the choice name value, not the label of the selected choice.  If you want to display the label of the selected choice, then I suggest you use a calculate using the jr:choice-name() function.

Support for the XLSForm jr:choice-name() function was introduced in Survey123 in version 3.1 in both the field and web Survey123 apps.  This function takes two inputs: a string representing a choice name, and a second string representing the name of the select question. Note that the second parameter requires you to enclose the question with quotes.

The output of this function is the label of the choice name passed-in.  If this function is used in a multi-language survey, the label returned is that of the active language.  

  • Select_multiple questions: Select_multiple questions let you choose one or more values from a predefined list. The output of a select_multiple question is a comma-separated string representing all the values selected by the user. This output, as is, is not the easiest to handle with dynamic labels, but again you can use other calculate questions to properly massage the output before it is added to your question label.  The https://community.esri.com/groups/survey123/blog/2017/08/30/understanding-multiple-choice-questions-...  blog post describes in more detail how multiple choice questions behave and how you can work and control its outputs.

Other things to consider


There are some obvious and not so obvious things to consider when working with dynamic labels:

  • If you reference in your label a question for which the user has not provided an answer, then your question is going to have some missing text.  You can choose to be clever with the label. For example, in our Water Violation Example it is not evident when the violation type is missing. You will either read “Photo of the violation” (No violation type chosen) or “Photo of the Broken Pipe violation” (if Broken Pipe has been chosen).  In practice, you will not always get so lucky when the variable is missing.  In the pipe cost repair example above, it is evident that we are missing something in the total cost note when a dollar amount is not present.  You can choose to use a relevant statement to hide questions with dynamic labels until the variable to be replaced (in our example the cost or repair) has a valid value. In these cases, you can use the string-length() function as shown in the following example.

  • Your dynamic labels will certainly look great in the survey, but what about when you bring your survey layers into web maps? Or when you look at your survey data in the Survey123 website? On this one, it is important to understand what really happens when your survey is published, and how the Survey123 website as well as other ArcGIS apps work with your survey layers.

When you publish an XLSForm document with Survey123 Connect, we take the values in the name column of your survey spreadsheet and we use them to create new fields in the survey feature layer.  By default, we use the contents of the label XLSForm column to define the field aliases of your attribute fields.  Typically, ArcGIS apps will use the field alias for display purposes. This is the case in the popup of a web map as well as throughout the Survey123 website.

When you insert a dynamic label, your field aliases will include the variable placeholder and that will not look very nice.  If you are worried about this, make sure you set the alias value for your attribute fields in the esri::bind:esriFieldAlias XLSForm column.  Alternatively, you can also refine the field aliases, after the survey is published, from the Item Details page of the feature layer item.

If used wisely, dynamic labels can help you build better and more user friendly smart forms.  We hope this new feature is useful to you!

Occasional Contributor III

Thanks team! I love these new features

Attached below is a screenshot of how I've improved one of my existing surveys using the jr:choice-name() function.

*Location details is a calculation of multiple select_one questions

Before and After jr:choice-name() Functions

Occasional Contributor III

Maybe you meant to write ${violationtype_label} ...Ismael Chivite 



Esri Frequent Contributor

Thanks Stefano! Fixed screenshot in the post!

Occasional Contributor


Does it work with the pulldata function?


Very nice post, thanks!

I had been using this feature as a way to check the value of hidden calculations while developing surveys, but it hadn't occurred to me to use it in the survey itself.

New Contributor II

I'm sorry if this question was already asked, but what about select_one questions that are embedded in repeats?  It is pretty straight forward using jr:choice-name(${dom_species},'${dom_species}') to pull out the correct label of my choice for Dominant Species, but am I able to aggregate them? 

My example would be if I have a select one question based on dominant species within a transect, but I have to take 5 transects for the total plot.  I have three dominant species choices, Oak, Maple, Tamarack, after I record responses for all 5 transects can I pull out the answers: Tamarack, Oak, Oak Oak, Maple?

Thank you!


Esri Esteemed Contributor

Hi Rob,

It would be easiest to have a calculate question inside the repeat look up the label selected for the question and then have another calculate question outside of the repeat use the join() function to concatenate the labels of the answers togethers

New Contributor II


Within the repeat I would use the calculation jr:choice-name(${dom_species},'${dom_species}')

then outside the repeat i would use the calculation join(${repeat_answer}) as a text type?

I can't seem to aggregate the calculation.  I guess I cannot even get the join() to return an answer.


Esri Frequent Contributor

Hi Robert Geitner‌   The join function takes two arguments: the separator, and the question you want to aggregate.


If you omit the separator parameter, you will get always null values in the output of your calculation, which I believe it is what is happening to your expression.

Below is a more complete example.

I hope this helps.

New Contributor II

Thank you so much for the help Ismael!  Works great!

New Contributor II


I am having a hard time figuring out another calculation.  I am using a select_one to chose a tree type, and then the next line is an integer Spinner so folks can fill out a percentage value.  I had a hard time getting that number to do a final 'total' calculation so I followed up with another line to 'calculate' the value so the final 'Total Percentage' is a summation of all 8 dominant tree values.  The issue comes in that the final total calculation only works if you complete all 8 spinners.  I set the default values to 0, hoping that would return a final total, but I can't seem to get it to work.  Help?

New Contributor II

I believe I found the answer.  Thank you though!

coalesce(${p1},0) + coalesce(${p2},0) + coalesce(${p3},0) + coalesce(${p4},0) + coalesce(${p5},0) + coalesce(${p6},0) + coalesce(${p7},0) + coalesce(${p8},0) + coalesce(${p0},0)