docassemble allows you to format your text using Markdown and to
use Mako to make your text “smart.” These mark up methods are
available for use in question
text, field labels, interview
help
text, the content of documents, and other text elements.
Markdown
The syntax of Markdown is explained well elsewhere.
When generating documents from Markdown, docassemble uses Pandoc to convert Markdown to PDF, RTF, and HTML. (Unless you are using Microsoft Word templates, in which case you will use the Jinja2 templating language in the Word document.)
Here are some examples of things you can do with Markdown.
question: Markdown demonstration
subquestion: |
This is *italic text*.
This is **bold text**.
This is __also bold text__.
> This is some block-quoted
> text
### This is a heading
This is an image from the internet:

Here is a bullet list:
* Apple
* Peach
* Pear
Here is a numbered list:
1. Nutmeg
2. Celery
3. Oregano
Here is a
[link to a web site](http://google.com).
mandatory: true
All of these types of markup will format text in questions as well as
text in assembled documents (with the exception of the !
image
insertion command, which does not work within PDF and RTF documents).
Using Mako for logic and generated text
docassemble uses a templating system called Mako to allow developers to insert variables and code into questions and documents.
You can insert the values of variables into question text using Mako’s
${ ... }
syntax.
mandatory: True
question: |
A summary
subquestion: |
You like ${ favorite_fruit }
and ${ favorite_vegetable }.
---
code: |
favorite_fruit = 'apples'
favorite_vegetable = 'potatoes'
You can use Mako’s if/endif
syntax to insert text conditionally:
mandatory: True
question: |
Hello!
subquestion: |
I hope you are having a good day.
% if day_of_month == 1:
Don't forget to change your wall calendar!
% endif
You can also express more complicated logic:
mandatory: True
question: |
Commentary on the day of the month
subquestion: |
Let me tell you about today.
% if day_of_month < 3:
The month just started!
% elif day_of_month < 15:
It is the beginning part of
the month.
% else:
It is the latter part of the month.
% endif
The Mako syntax for if/then/else statements is based on
Python’s if
statement, but is a little bit different.
The %
at the beginning of the line signifies that you are doing
something special with Mako.
Python itself does not use endif
– it only uses indentation to
designate where the if/then/else statement ends. Mako requires the
use of endif
because it does not see indentation.
In Python, elif
is short for “else if.” In the example above, the
if/then/else statement means:
If the day of the month is less than three, write “The month just started!”, but otherwise if the day of the month is less than 15, write “It is the beginning part of the month.”; otherwise, write “It is the latter part of the month.”
As with Python, it is critical that you include :
at the end of
any line where you indicate a condition.
You can put if/endif
statements inside of other if/endif
statements:
mandatory: True
question: |
Commentary on the day of the month
subquestion: |
Let me tell you about today.
% if day_of_month < 3:
The month just started!
% elif day_of_month < 15:
It is the beginning part of
the month.
% else:
% if month_of_year == 12:
It is almost New Year's!
% else:
It is the latter part of the month.
% endif
% endif
In this example, the % if
, % else
, and % endif
lines are
indented, but they do not have to be. Since nested if/then/else
statements can be hard to read, the indentation helps make the
statement more readable. Note that the the actual text itself is not
indented, even though the %
lines are indented; this is because
indentation means something in Markdown. If you indent a line by
four spaces, Markdown will treat the line as a code block, which
might not be what you want.
Mako also allows you to work with lists of things
using % for
and % endfor
:
mandatory: True
question: |
Foods I like
subquestion: |
% for food in ['plums', 'pears', 'peas']:
I like ${ food }.
% endfor
This is based on Python’s for
statement.
The for
loop is useful for working with groups of objects:
modules:
- docassemble.base.legal
---
objects:
- witness: PartyList
---
mandatory: True
question: |
The ${ witness.as_noun() }
subquestion: |
% for person in witness:
${ person } is a witness.
% endfor
---
question: |
What is the name of the
${ ordinal(i) } witness?
fields:
- First Name: witness[i].name.first
- Last Name: witness[i].name.last
---
question: |
Are there any other witnesses?
yesno: witness.there_is_another
Within for
loops, Mako provides a useful object called loop
,
which contains information about the current iteration of the loop.
mandatory: True
question: |
Foods I like
subquestion: |
% for food in ['apples', 'peaches', 'pears', 'plums', 'turnips', 'raspberries']:
% if loop.first:
First, I like ${ food }.
% elif loop.last:
Last but not least, I am a
big fan of ${ food }.
% elif loop.even:
I also like ${ food }.
% elif loop.odd:
The ${ ordinal(loop.index) } food
I like is ${ food }.
% endif
% endfor
Note that loop.index
is a number in a range that starts with zero.
The ordinal()
function converts these numbers to words.
For more information about working with groups of things, see groups.
In addition to allowing you to insert Python expressions with the ${
... }
syntax, Mako allows you to embed Python statements using
the <%
/%>
syntax:
mandatory: True
question: |
<%
a = 2
b = 3
the_answer = a + b
%>
The answer is ${ the_answer }.
Mako also allows you to insert special code that cuts short the text being rendered:
mandatory: True
question: |
Apples
subquestion: |
% if not likes_apples:
Oh well, never mind.
<% return STOP_RENDERING %>
% endif
Apples are red.
They can also be green.
They have stems and seeds.
They are juicy and sweet.
The same thing could also be accomplished with an else
statement,
but using STOP_RENDERING
may be more readable.
For more information about Mako, see the Mako documentation. Note, however, that not all features of Mako are available in docassemble. For example, in normal Mako, you can write:
% if some_variable is UNDEFINED:
...
% endif
In docassemble, this will not work as intended. Instead, you
would use the defined()
function:
% if not defined('some_variable'):
...
% endif
If you want to use the <%def>
construct of Mako, see the
def
initial block.
Formatting variables
When the variable you insert with ${ ... }
is a number, the way that
it is formatted may not be to your liking. There are a variety of
ways to format numbers in Python.
code: |
monthly_income = 43143.26/12
---
question: |
Your monthly income
subquestion: |
Your monthly income is
${ monthly_income }
dollars per month.
But it would be better to say
your monthly income is
${ '%.2f' % monthly_income }
dollars per month, or
${ '{:.2f}'.format(monthly_income) }
dollars per month, or
${ '{:,.2f}'.format(monthly_income) }
dollars per month, or
${ int(monthly_income) }
dollars per month, or
best of all,
${ currency(monthly_income) }
per month.
mandatory: True
Inserting images
To insert an image that is located in the static
folder of a custom
Python package, use the FILE
command. This works within PDF, RTF,
and DOCX documents as well as within questions.
For example:
---
question: |
Did your attacker look like this?
subquestion: |
Please study the face below closely before answering.
[FILE docassemble.crimesolver:mugshot.jpg]
yesno: suspect_identified
This example presumes that there is a Python package called
docassemble.crimesolver
installed on the server, and there is a file
mugshot.jpg
located within the static
directory inside that
package.
If you omit the package name (e.g., [FILE mugshot.jpg]
),
docassemble will assume you are referring to a file located in the
static
directory of the package in which the question appears.
Optionally, you can set the width of the image:
[FILE docassemble.crimesolver:mugshot.jpg, 100%]
or:
[FILE docassemble.crimesolver:mugshot.jpg, 150px]
You can also set the alt text of the image:
[FILE docassemble.crimesolver:mugshot.jpg, 150px, Mugshot photograph]
If you want to set the alt text without setting a width, use None
(with a capital N) as the width:
[FILE docassemble.crimesolver:mugshot.jpg, None, Mugshot photograph]
You can use any characters in the alt text except for the right
bracket. If you need to use the right bracket in alt text, use one
of the other methods of inserting images, such as creating a
DAStaticFile
object.
To insert an image that has been uploaded, or created using a signature field, simply refer to the variable using Mako. For example:
question: |
Please upload a picture of yourself.
fields:
- Picture: user_picture
datatype: file
---
question: |
You're so adorable, François!
subquestion: |
${ user_picture }
mandatory: True
Alternatively, you can call the show()
method on the file object:
question: |
You're so adorable!
subquestion: |
${ user_picture.show() }
mandatory: True
The show()
method takes an optional argument, width
:
question: |
You're so adorable!
subquestion: |
${ user_picture.show(width='250px') }
mandatory: True
In the above example, the picture will be shrunk or expanded so that its width is 250 pixels.
Inserting inline icons
If you have defined “decorations” in an image sets
block (see
initial blocks), you can include these decorations as icons (having
the same size as the text) by referencing them “emoji-style,” putting
colons around the decoration name. This works not only in question
and subquestion
areas, but also in question choices.
This works within PDF and RTF documents as well as within questions.
image sets:
freepik:
attribution: |
Icon made by [Freepik](http://www.flaticon.com/authors/freepik)
images:
male: male244.svg
female: female243.svg
---
question: |
What is your gender?
field: user.gender
choices:
- "Male :male:": male
- "Female :female:": female
- "Other": other
By default, if an “emoji-style” reference refers to an image that has
not been defined in an image sets
or images
block, the
reference will be treated as a reference to a Font Awesome icon.
mandatory: True
decoration: chart-bar
question: |
Third quarter metrics
subquestion: |
We are making more money
:far-fa-money-bill-alt: than
we did in the second quarter.
So you can sleep well tonight! :bed:
As explained in the Configuration, only one “style” of Font Awesome icon (by default, the “solid” style) can be used at one time. If you need to use a different “style” for a particular icon, or you want to apply additional formatting to an icon, you can include the raw HTML for the icon. For example:
---
question: |
Social media usage
subquestion: |
Do you use <i class="fab fa-facebook-f"></i>?
yesno: user_is_on_facebook
---
Note that while ordinary inline icon references work in documents as well as on the web, Font Awesome references only work in questions, not in documents.
Inserting audio and video
In addition to using the audio
and video
question modifiers, you can
insert audio and video into your Mako text in questions.
question: Upload an audio file.
fields:
- no label: my_file
datatype: microphone
---
mandatory: True
question: Listen to this!
subquestion: |
Best song ever:
${ my_file }
Don't you think so?
Or, if you have a file in data/static
, you can write:
---
question: Listen to this!
subquestion: |
This excerpt of whalesong will give you goosebumps.
[FILE whale_song.mp3]
---
It works the same with videos.
---
question: Watch this!
subquestion: |
This video of otters sunbathing is going to go viral.
[FILE awesome_otters.mp4]
---
You can also embed YouTube and Vimeo videos (which is far
preferable to working with video files, which are enormous). For
example, if you want to embed a YouTube video for which the URL is
https://www.youtube.com/watch?v=RpgYyuLt7Dx
or
https://youtu.be/RpgYyuLt7Dx
, you would write this:
---
question: Are you traveling to New York City?
yesno: going_to_nyc
video: |
New York is such a happening place. Check it out:
[YOUTUBE RpgYyuLt7Dx]
---
See question modifiers for more information about including audio and video.
Inserting QR codes
You can also display or insert QR codes using [QR ...]
, where ...
is the text you want to encode. This works like [FILE ...]
in that
you can give the image a width and alt text. The QR code images can
be displayed on the screen or inserted into a document.
This works within PDF and RTF documents as well as within questions.
For example, this interview provides a QR code that directs the user to Google News:
mandatory: True
question: Here is a URL for you in a QR code
subquestion: |
[QR https://news.google.com, 200px, Google News]
attachment:
name: Your QR code
filename: your_code
content: |
Use the QR reader on your smartphone to take a picture of this:
[QR https://news.google.com]
See also the qr_code()
function, which allows you to insert the
[QR ...]
markup using Python.
Inserting other types of files
Just as you can insert images with [FILE
docassemble.crimesolver:mugshot.jpg]
or ${ user_picture }
, you can
also insert other types of files.
If you insert a text file (MIME type text/plain
), the raw contents
of the file will be inserted.
If you insert a Markdown file (MIME type text/markdown
), the
contents of the file will be treated as a DATemplate
.
The behavior when you insert a PDF file depends on the context:
- In a
question
, the user will see a thumbnail of the first page of the document, and clicking the thumbnail will open the PDF file. - In a document created by converting Markdown to PDF, the PDF pages will be inserted into the document.
- When assembling documents in other formats, the pages of the PDF will be converted to images and inserted into the document in the same way images are inserted.
When you insert a word processing file, the file will be converted to
PDF and inserted into the document the way a PDF file is inserted.
However, if you include a DOCX file inside a DOCX file created using
docx template file
, the result is like that of calling
include_docx_template()
.
Inserting tables
Tables can be inserted in the format known as PHP Markdown Extra.
mandatory: true
question: |
Your fruit inventory
subquestion: |
This describes your fruit
collection.
Fruit | How many
-------|---------
Apple | 4
Orange | 3
Pear | 6
If you want to construct a table based on information in a list, the
best practice is to collect the list information into an object and
then use the table
block to create a template for the table.
If you want to write tables in Markdown manually, note that the alignment characters do not have do be perfectly aligned from row to row.
mandatory: true
question: |
Your vegetable inventory
subquestion: |
This describes your vegetable
collection.
Vegetable|How many
------|----
Potato|4
Brocolli|3
Beet|6
Under the Markdown rules, the text for each row needs to be all on
the same line in your Markdown text. If you want to include a line
break within a cell, use the [BR]
tag, which is documented in the
document markup section.
Exactly how your text is converted from Markdown into an actual table depends on the output format. If you are including a table that is viewed on the screen, see tables in HTML for the details. If you are including a table that is inserted into an attachment, see tables in attachments.
If you want to have fine-grained control over the formatting of tables, Markdown will disappoint you.
For example, the PHP Markdown Extra format requires that you include a header in your table, even if you do not want one. You can try to make the header row blank with the following trick.
mandatory: true
question: |
Your vegetable inventory
subquestion: |
This describes your vegetable
collection.
| | |
|---------|------|
|Potato |4 |
|Brocolli |3 |
|Beet |6 |
If you want a very specific type of table, you can use raw HTML for
a table that displays in a question or raw LaTeX for a table that
displays in a PDF-only attachment
.
If you want a simple two-column table that fills the width of the
page, note that there are special document markup tags for this
special case: you can write [BEGIN_TWOCOL]
(text of first column)
[BREAK]
(text of second column) [END_TWOCOL]
.
Embedding fields
In a fields
block, you can use the markup syntax [FIELD ...]
to
embed fields within the within the subquestion
text. For more
information about this feature, see the section on
Embedding fields within a paragraph.
Embedding areas for interim information
If you include the markup [TARGET ...]
within text, you will create
an invisible area where text can be placed by code
. For more
information about this feature, see the section on
Processing interim user input.