Ampscript HTML Table
If you find yourself building internal tools like for non-SFMC users, you might need to display some data from SFMC in an table (either on a CloudPage or sent in an email to your team).
Rather than reinvent the wheel each time the need arises, I decided to build a reusable snippet that does the following:
- builds a HTML table ready to be placed anywhere on the page with a single variable
- uses both
<th>
and<td>
HTML elements for improved readability and styling support - allows to easily decide what column to display and in which order they should be
Tabularize anything!β
Want to grab some data from a data view and display it on a CloudPage or in an Email? Here's an example that looks for all subscribers with a hard-coded email address.
%%[
/* Define the columns to display */
set @columns = ""
set @columns = Concat(@columns, ",", "SubscriberKey")
set @columns = Concat(@columns, ",", "Status")
set @columns = Concat(@columns, ",", "DateUnsubscribed")
set @columns = Concat(@columns, ",", "DateUndeliverable")
set @columns = Concat(@columns, ",", "BounceCount")
set @colSet = BuildRowsetFromString(@columns, ',')
/* Grab the data */
set @emailAddress = 'example@example.com'
set @tableData = LookupRows('ENT._Subscribers', 'EmailAddress', @emailAddress))
/* Build the HTML Table */
set @tableHTML = "<table>"
IF RowCount(@colSet) > 0
THEN
set @tableHTML = Concat(@tableHTML, "<thead><tr>")
FOR @c = 2 TO RowCount(@colSet) DO
set @column = Field(Row(@colSet, @c), 1)
set @tableHTML = Concat(@tableHTML, "<th>", @column, "</th>")
NEXT @c
set @tableHTML = Concat(@tableHTML, "</tr></thead>")
IF RowCount(@tableData) > 0
THEN
set @tableHTML = Concat(@tableHTML, "<tbody>")
FOR @r = 1 TO RowCount(@tableData) DO
set @tableHTML = Concat(@tableHTML, "<tr>"))
set @row = Row(@tableData, @r))
FOR @d = 2 TO RowCount(@colSet) DO
set @column = Field(Row(@colSet, @d), 1)
set @tableHTML = Concat(@tableHTML, "<td>", Field(@row, @column), "</td>")*/
NEXT @d
set @tableHTML = Concat(@tableHTML, "</tr>"))
NEXT @r
set @tableHTML = Concat(@tableHTML, "</tbody>")
ENDIF
ENDIF
set @tableHTML = Concat(@tableHTML, '</table>')
]%%
%%=v(@tableHTML)=%%
How it worksβ
The code requires two things to work: data and column names in the order in which you want to display them.
Columns and their orderβ
For the script to work, we need to provide it the names of the fields that should become table columns. In the end they need to be stored in their own row set (or @colSet
...) to allow the script to loop through their names.
set @columns = ""
set @columns = Concat(@columns, ",", "SubscriberKey")
set @columns = Concat(@columns, ",", "Status")
set @columns = Concat(@columns, ",", "DateUnsubscribed")
set @columns = Concat(@columns, ",", "DateUndeliverable")
set @columns = Concat(@columns, ",", "BounceCount")
set @colSet = BuildRowSetFromString(@columns, ',')
Sure, this will result in a string starting with a comma:
",SubscriberKey,Status,DateUnsubscribed,DateUndeliverable,BounceCount"
Don't worry - the script further down the line is ready for that - it will ignore the first rowSet that would be empty and start with the the second one instead.
The concatenation here is designed to support easy column reordering while you work with the code - just reorder the columns like this to influence the final column output order in the generated HTML table:
To quickly move the order of rows like this in Visual Studio: just select the row and press CTRL+β
or CTRL+β
simultanously on your keyboard
Data inputβ
The code will work with any ampscript function that returns a set of or rows:
- LookupRows
- LookupRowsCS
- LookupOrderedRows
- LookupOrderedRowsCS
- RetrieveSalesforceObjects
- RetrieveSalesforceJobSources
- BuildRowSetFromJSON (see the example below)
In most cases the order of defining columns and getting data is interchangable, but it makes sense to define the columns first when using the RetrieveSalesforceObjects
function - you can actually use the @colSet
variable as parameter to define which columns to retrieve, for example:
RetrieveSalesforceObjects('Orders', @colSet, 'PersonContactId', '=', _subscriberkey)
Example with BuildRowSetFromJSONβ
Imagine you're tasked with creating an email with a table displaying details of party 4 characters in an RPG game.
Sample JSONβ
You get the JSON from an API and it looks like this:
{
"crmSpecialists": [
{
"name": "John Smith",
"nickname": "The Enchanter",
"function": "Customer Acquisition",
"department": "Sales",
"ultimateSkill": "Mind Manipulation"
},
{
"name": "Jane Johnson",
"nickname": "The Keeper",
"function": "Customer Retention",
"department": "Marketing",
"ultimateSkill": "Eternal Loyalty"
},
{
"name": "Michael Brown",
"nickname": "The Oracle",
"function": "Data Analysis",
"department": "Analytics",
"ultimateSkill": "Infinite Insight"
},
{
"name": "Emily Davis",
"nickname": "The Architect",
"function": "CRM Implementation",
"department": "Operations",
"ultimateSkill": "Seamless Integration"
}
]
}
You store the value in the @jsonString
variable (normally we don't hard-code data like this, but this is just an example):
%%[
set @jsonString = '{
"crmSpecialists": [
{
"name": "John Smith",
"nickname": "The Enchanter",
"function": "Customer Acquisition",
"department": "Sales",
"ultimateSkill": "Mind Manipulation"
},
{
"name": "Jane Johnson",
"nickname": "The Keeper",
"function": "Customer Retention",
"department": "Marketing",
"ultimateSkill": "Eternal Loyalty"
},
{
"name": "Michael Brown",
"nickname": "The Oracle",
"function": "Data Analysis",
"department": "Analytics",
"ultimateSkill": "Infinite Insight"
},
{
"name": "Emily Davis",
"nickname": "The Architect",
"function": "CRM Implementation",
"department": "Operations",
"ultimateSkill": "Seamless Integration"
}
]
}'
Converting the array into a rowsetβ
You use the new BuilRowsetFromJSON function to get the contents of the crmSpecialists
array.
/* Convert the JSON string into a set of rows */
set @tableData = BuildRowSetFromJSON(@jsonString, '$.crmSpecialists[*]', 1)
If you want to learn more about this new feature- go check out those excellent resources:
- Cameron Robert's video on the function: AMPscript BuildRowSetFromJSON Function in Salesforce Marketing Cloud
- Gortonington's article on How BuildRowsetFromJSON() can make your life so much better
Defining the columnsβ
Now that the rowset is created we just need to define which of the values we want to have displayed in our table. Here you can easily change the order or ommit some values that you don't want to see.
/* Specify the columns to display */
set @columns = ""
set @columns = Concat(@columns, ",", "nickname")
set @columns = Concat(@columns, ",", "name")
set @columns = Concat(@columns, ",", "function")
set @columns = Concat(@columns, ",", "department")
set @columns = Concat(@columns, ",", "ultimateSkill")
set @colSet = BuildRowsetFromString(@columns, ',')
HTML generation & outputβ
/* Build the Table */
set @tableHTML = "<table>"
IF RowCount(@colSet) > 0
THEN
set @tableHTML = Concat(@tableHTML, "<thead><tr>")
FOR @c = 2 TO RowCount(@colSet) DO
set @column = Field(Row(@colSet, @c), 1)
set @tableHTML = Concat(@tableHTML, "<th>", @column, "</th>")
NEXT @c
set @tableHTML = Concat(@tableHTML, "</tr></thead>")
IF RowCount(@tableData) > 0
THEN
set @tableHTML = Concat(@tableHTML, "<tbody>")
FOR @r = 1 TO RowCount(@tableData) DO
set @tableHTML = Concat(@tableHTML, "<tr>"))
set @row = Row(@tableData, @r))
FOR @d = 2 TO RowCount(@colSet) DO
set @column = Field(Row(@colSet, @d), 1)
set @tableHTML = Concat(@tableHTML, "<td>", Field(@row, @column), "</td>")*/
NEXT @d
set @tableHTML = Concat(@tableHTML, "</tr>"))
NEXT @r
set @tableHTML = Concat(@tableHTML, "</tbody>")
ENDIF
ENDIF
set @tableHTML = Concat(@tableHTML, '</table>')
]%%
%%=v(@tableHTML)=%%
With the %%=v(@tableHTML)=%%
output we would get the following HTML
(formatted with white space and line breaks for readability):
<table>
<thead>
<tr>
<th>name</th>
<th>nickname</th>
<th>function</th>
<th>department</th>
<th>ultimateSkill</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Smith</td>
<td>The Enchanter</td>
<td>Customer Acquisition</td>
<td>Sales</td>
<td>Mind Manipulation</td>
</tr>
<tr>
<td>Jane Johnson</td>
<td>The Keeper</td>
<td>Customer Retention</td>
<td>Marketing</td>
<td>Eternal Loyalty</td>
</tr>
<tr>
<td>Michael Brown</td>
<td>The Oracle</td>
<td>Data Analysis</td>
<td>Analytics</td>
<td>Infinite Insight</td>
</tr>
<tr>
<td>Emily Davis</td>
<td>The Architect</td>
<td>CRM Implementation</td>
<td>Operations</td>
<td>Seamless Integration</td>
</tr>
</tbody>
</table>
This would be displayed like this:
when used with the following CSS:
<style>
*{font-family: monospace}
td, th{padding: 8px}
</style>
Full Example Codeβ
Here's just the full code if you want to play around with it.
%%[
set @jsonString = '{
"crmSpecialists": [
{
"name": "John Smith",
"nickname": "The Enchanter",
"function": "Customer Acquisition",
"department": "Sales",
"ultimateSkill": "Mind Manipulation"
},
{
"name": "Jane Johnson",
"nickname": "The Keeper",
"function": "Customer Retention",
"department": "Marketing",
"ultimateSkill": "Eternal Loyalty"
},
{
"name": "Michael Brown",
"nickname": "The Oracle",
"function": "Data Analysis",
"department": "Analytics",
"ultimateSkill": "Infinite Insight"
},
{
"name": "Emily Davis",
"nickname": "The Architect",
"function": "CRM Implementation",
"department": "Operations",
"ultimateSkill": "Seamless Integration"
}
]
}'
/* Convert the JSON string into a set of rows */
set @tableData = BuildRowSetFromJSON(@jsonString, '$.crmSpecialists[*]', 1)
/* Specify the columns to display */
set @columns = ""
set @columns = Concat(@columns, ",", "nickname")
set @columns = Concat(@columns, ",", "name")
set @columns = Concat(@columns, ",", "function")
set @columns = Concat(@columns, ",", "department")
set @columns = Concat(@columns, ",", "ultimateSkill")
set @colSet = BuildRowsetFromString(@columns, ',')
/* Build the Table */
set @tableHTML = "<table>"
IF RowCount(@colSet) > 0
THEN
set @tableHTML = Concat(@tableHTML, "<thead><tr>")
FOR @c = 2 TO RowCount(@colSet) DO
set @column = Field(Row(@colSet, @c), 1)
set @tableHTML = Concat(@tableHTML, "<th>", @column, "</th>")
NEXT @c
set @tableHTML = Concat(@tableHTML, "</tr></thead>")
IF RowCount(@tableData) > 0
THEN
set @tableHTML = Concat(@tableHTML, "<tbody>")
FOR @r = 1 TO RowCount(@tableData) DO
set @tableHTML = Concat(@tableHTML, "<tr>"))
set @row = Row(@tableData, @r))
FOR @d = 2 TO RowCount(@colSet) DO
set @column = Field(Row(@colSet, @d), 1)
set @tableHTML = Concat(@tableHTML, "<td>", Field(@row, @column), "</td>")*/
NEXT @d
set @tableHTML = Concat(@tableHTML, "</tr>"))
NEXT @r
set @tableHTML = Concat(@tableHTML, "</tbody>")
ENDIF
ENDIF
set @tableHTML = Concat(@tableHTML, '</table>')
]%%
%%=v(@tableHTML)=%%