Dotdown™

Build a form by typing

Dotdown™ is a tiny text format for forms. Type a dot and a field type, and the field is there. It is built into the form editor, so there is nothing to install.

# Event signup
.text Your name*
.email Email*
.select Plan: Free, Pro, Team

How it works

  1. Open the box

    On the New form or Edit form page, open “Dotdown™” next to the Fields heading. On a phone it is already open when you create a form.

  2. Type a dot

    A menu of field types appears. Pick one with Enter, Tab or a tap, or just type the whole line yourself. Typing / works too, and the menu will still give you the dot version.

  3. Press Enter

    Every time you start a new line, the form below updates to match what you typed. You can also click “To form ⤵”, or press ⌘/Ctrl + Enter.

  4. Go back and forth

    Open the box on a form you already have and it fills itself with that form as text. Edit the field rows, close and reopen the box, and the text catches up.

Title, description and tags

The top of the form is its info. Put it between two --- lines and everything below is fields.

---
Event signup
Please fill this in.
#event #feedback
---
.text Your name*
.email Email*
  • The block is the first thing in the box, between two --- lines.
  • Inside it, position decides: the first line is the title, the next lines are the description, and a line of #words is the tags.
  • A # in front of the title is fine too, so # Event signup works.
  • Everything after the closing --- is fields.
  • Tags have no spaces. A tag typed as “my tag” in the form shows up here as #my-tag.
  • The block is optional. A form with just a title can start with # Title.

Required or optional

A field is optional unless you mark it. A * at the end of the label makes it required.

.text Full name*
.text Nickname
.select Plan*: Free, Pro, Team
.email*
  • For choices, put the star before the colon: .select Plan*: Free, Pro.
  • With no label, put it right after the type: .email* gives a required field called Email.
  • It works on every input field, including totals, groups and doodles.
  • Text blocks, dividers and images have nothing to fill in, so they have no star.
  • Visitors see a * next to required fields, so the star you type is the star they see.

The shape of a line

.text Your name

A line starting with a dot is a field: .type, then the label.

## Your details

A plain line, or a line starting with ##, becomes a text block between fields.

# Event signup

With no form-info block (above), a first line starting with # is the form title and the plain line after it is the description.

A few shortcuts

  • Chain fields on one line.

    .text Full name .number Quantity .email Email
    // .text Full name
    // .number Quantity
    // .email Email
  • Skip the label and you get a sensible one.

    .email
    // .email Email
    .tel
    // .tel Phone
    .url
    // .url Website
  • An unknown word becomes a text field.

    .first_name
    // .text First name
    .nickname
    // .text Nickname
  • Add * to the end of a label to make the field required. No star means optional.

    .email Work email*
    // required
    .text Nickname
    // optional
  • Choices go after a colon, separated by commas.

    .select Plan: Free, Pro, Team
    // a dropdown with 3 choices
  • Pre-fill a field with = after the label. See Default values below.

    .text Country = Malaysia
    // starts as Malaysia
    .select Plan = Pro: Free, Pro, Team
    // Pro is pre-selected
    .checkbox Extras = Meals, Bus: Meals, Bus, Hotel
    // Meals and Bus are ticked

Syntax for every field

The label is whatever you want visitors to see. A field is optional unless its label ends with *.

Text and numbers

.text

A one-line text answer.

.text Label
// example
.text Full name*

.textarea

A longer, multi-line answer.

.textarea Label
// example
.textarea Anything else?
  • A bare .textarea is labelled “Message”.

.number

A number. Totals and repeating groups count from a number field.

.number Label
// example
.number Guests

.email

An email address.

.email Label
// example
.email Work email*
  • A bare .email is labelled “Email”.

.tel

A phone number.

.tel Label
// example
.tel Mobile
  • A bare .tel is labelled “Phone”.

.url

A web address.

.url Label
// example
.url Portfolio
  • A bare .url is labelled “Website”.

Dates and ratings

.date

A date picker.

.date Label
// example
.date Birthday

.time

A time picker.

.time Label
// example
.time Pickup time

.rating

A rating from 1 to 5.

.rating Label
// example
.rating How was it?

Choices

.select

A dropdown. Visitors pick one.

.select Label: Choice 1, Choice 2
// example
.select Plan*: Free, Pro, Team
  • You have to list the choices.
  • To make the field required, put the * before the colon, as in .select Plan*: A, B

.radio

Buttons. Visitors pick one, and all choices stay visible.

.radio Label: Choice 1, Choice 2
// example
.radio Size*: small, medium, big
  • You have to list the choices. The * goes before the colon.

.checkbox

Without choices, one yes/no box. With choices, a list where visitors can tick as many as they like.

.checkbox Label
.checkbox Label: Choice 1, Choice 2
// example
.checkbox I agree to the terms*
.checkbox Topics: News, Offers, Events
  • There is no separate multi-select type. This is it.

Files, photos and drawings

.file

An upload: a PDF or an image, up to 10MB. It is emailed to you.

.file Label
// example
.file Resume*

.camera

A big button to take a photo, or choose one from the device. Up to 10MB.

.camera Label
// example
.camera Photo of the damage

.signature

A box to sign in, with a finger or the mouse.

.signature Label
// example
.signature Sign here*

.doodle

Visitors draw on top of an image, like a floor plan or a body outline.

.doodle Label: https://link-to-image
// example
.doodle Mark the damage: https://example.com/car.png
  • The image link must be public. A bare link, with no label, gives a field called “Doodle”.

Content between fields

.description

A block of text, not an input. Use it for instructions.

.description Your text
// example
.description Please read this before you start.
  • A plain line, or a line starting with ##, does the same thing.
  • A bare .description, with no text after it, is a text input called “Description”.

.page

Starts a new page with Next and Back buttons.

.page Title > target
// example
.page Payment
  • Title and > target are both optional. See Pages and jumps below for the full logic.

.divider

A line that splits the form into parts.

.divider

.image

A picture shown in the form.

.image https://link-to-image Alt text
// example
.image https://example.com/logo.png Our logo
  • The link must be public. The alt text is optional.

Totals and repeating groups

.tally

A running total: a number field multiplied by a price.

.tally Label: Number field x Price
// example
.number Guests
.tally Total: Guests x $25
  • The number field has to exist, and the name must match its label.
  • Put a unit in front of the price ($25, RM25). It is shown in front of the total. A plain 25 is fine too.

.duplicate

A group of fields repeated once per unit of a number field, like one set per child or guest.

.duplicate Label: Number field { fields }
// example
.number Kids
.duplicate Child: Kids { .text Name .date Birthday }
  • The fields to repeat go inside { }, chained on one line.
  • A group cannot hold another group or a total.

.additive

A group where the visitor adds more copies with a button.

.additive Label { fields }
.additive Label: 5 { fields }
// example
.additive Review: 5 { .text Name .textarea Comment }
  • The number after the colon is an optional maximum.

Pages and jumps

Split a long form into pages, and send visitors to a different page depending on their answer. Planning a branching form? Read the .page guide.

1. Start a new page

.text Name*
.page Payment
.number Guests
.page Thanks
.textarea Anything else?
  • Fields before the first .page make page 1. Each .page starts the next one.
  • The title is optional. It is the page heading, and it is what jumps point to.
  • .page1 and .page01 are shortcuts for .page Page1 and .page Page01.

2. Jump on an answer

Put > and a page title (or submit) after a choice.

.radio Plan: Free > submit, Pro > Payment, Team
.page Payment
.number Guests
  • Pro > Payment Choosing Pro jumps to the page titled Payment.
  • Free > submit Choosing Free submits the form right there.
  • Team No jump, so it goes to the next page.
  • Only .radio and .select can jump. In the field rows, type the same thing in the options box.
  • Page titles and choices cannot contain a comma or a >, because those are the separators.

3. After this page

.text Name
.page Payment > Thanks
.number Guests
.page Shipping
.text Address
.page Thanks
.textarea Anything else?
  • > after a .page line says where to go after that page: a later page title, or submit.
  • In the example, Payment jumps over Shipping straight to Thanks. Shipping would only be reachable from a jump of its own, so Dotdown™ warns about it.
  • Leave it blank to go to the next page. The last page always submits, so you never need submit there.
  • Use > submit on an earlier page to end the form early.

4. Which jump wins

  1. The answer’s jump is used first.
  2. If the answer has no jump, the page’s own > is used.
  3. If neither is set, the visitor goes to the next page.
  4. If a page has several questions with jumps, only the last one counts.

5. Rules

  • Jumps only go forward. A jump back to an earlier page is an error, so a form can never loop.
  • The target has to be a page that exists, or submit. A typo is an error and lists the real page names.
  • Two pages cannot share a title.
  • Pages cannot go inside a { } group.

6. What visitors see

  • The visitor sees one page at a time, with Back and Next, and Submit on the last page.
  • The step label reads “Step 2 of 3”. Once any jump exists the total is not fixed, so it reads “Step 2”.
  • Required fields are checked when the visitor presses Next.
  • Pages a visitor skips are not checked and their answers are not sent. If they go back and change an answer, answers from pages they no longer reach are dropped.

7. Warnings you may see

These do not stop you applying the form:

  • A page with no fields.
  • A page no answer can lead to, so nobody would see it.
  • More than one question on a page with jumps. Only the last one counts.
  • A > on a checkbox, where jumps do not work.

Putting it together

---
Event signup
---
.text Name*
.radio Plan: Free > submit, Pro > Payment, Team
.page Payment
.number Guests
.tally Total: Guests x $25
.page Extras
.checkbox Newsletter

Free submits straight away. Pro and Team go on to Payment, then Extras.

Default values

Start a field with an answer already in it.

Text and numbers

.text Country = Malaysia
// starts as Malaysia
.number Guests = 1
// starts as 1

Choices

.select Plan = Pro: Free, Pro, Team
// Pro is pre-selected
.radio Size = Medium: Small, Medium, Large
.checkbox Extras = Meals, Bus: Meals, Bus, Hotel
// Meals and Bus are ticked
.checkbox Agree = yes
// a plain Yes/No box starts ticked

Rules

  • Write = and the value right after the label (and its star), before any colon: .text Country* = Malaysia.
  • Visitors see the value already filled in and can change it. It is sent like any answer they typed.
  • Choices: the default must match one of the choices (capitals do not matter). A value that matches nothing is simply ignored.
  • Checkbox groups can start with several ticked: = Meals, Bus. A plain Yes/No checkbox starts ticked with = yes (or true, on, 1).
  • A default on a select or radio with jumps counts as the answer, so Plan = Free with Free > submit submits unless the visitor changes it.
  • Not available on .file, .camera, .signature, .doodle, .tally and groups. You will see an error if you try.
  • In the row builder it is the "Default value" box under the label, and To text / To form keep it.

Putting it together

.text Name*
.text Country* = Malaysia
.select Plan = Free: Free > submit, Pro, Team
.checkbox Extras = Meals: Meals, Bus, Hotel

Country starts as Malaysia. Plan starts on Free, which submits straight away.

A whole form

Put it together and you get this.

---
Birthday party RSVP
Tell us who is coming.
#party #rsvp
---
.text Your name* .email Email*
.number Guests*
.duplicate Guest: Guests { .text Name* .select Meal: Chicken, Veggie }
.tally Total: Guests x $25
.textarea Anything we should know?

Thank-you page

After they submit, visitors see a short default message. Add .post to write your own.

.text Name*
.email Email*
.post Thanks, {Name}!
We will email {Email} the schedule this week.
.image https://example.com/confirmed.png
.link See what to bring: https://example.com/packing

Send them somewhere else

.text Name*
.post > https://example.com/thanks
  • Without .post, visitors see the default: “Thanks! Your response to …was sent.”
  • .post goes last. Everything after it is the thank-you page: the text after .post is the heading, and plain lines, .image, .divider and .link follow. A question after it is an error.
  • {Name} is replaced with what the visitor answered in the field called Name. It is blank if they skipped it. Use it in the heading, the text, or a link’s label. A name that matches no field gives a warning.
  • .post > https://… sends visitors to that address straight after they submit, so anything written under it is never shown. It has to start with http:// or https://.
  • Answers are never put into a link or redirect address, so a { } there is an error.
  • .link Label: https://… is a button. It works anywhere in the form, not only after .post.
  • In test mode (?test=1) the thank-you page is shown as normal, and a redirect shows where visitors would go without leaving.
  • In the field rows it is “Thank-you page” and “Link button” under Info.

Same name, separate columns

Labels have to be different, with one exception: the same name can be asked on pages that nobody visits together.

.select Ticket*: Student > Student details, Adult > Adult details
.page Student details > Thanks
.text Name*
// Name on the Student page
.page Adult details
.text Name*
// the same Name on the Adult page: one column
.page Thanks
.textarea Anything else?

Keep two apart with a #

.text Name#1*
// visitors see "Name"
.text Name#2*
// visitors see "Name" too, but it is a separate column
  • Two fields can have the same label when no visitor can see both pages, like the Student and Adult pages above. Their answers share one column in your CSV, Google Sheet and email.
  • Same page, or pages one visitor passes through, is an error: the second answer would overwrite the first. Dotdown shows buttons that fix it for you.
  • Add # and a word or number to the end of a label to keep two fields apart. Visitors see only the label before the #; your export keeps the whole thing, so you can tell the columns apart.
  • The # has to touch the word before it. Name#1 is hidden from visitors, but Room #2 (with a space) is shown as it is.
  • Put it before the star and the default: .text Name#1* = Alex.
  • When you use one, Dotdown adds a // Visitors see line above it, and the row builder shows “Visitors see: Name” under the label.

Good to know

The box has find and replace, go to line, comment toggle and line numbers. See Dotdown™ editor keys.

  • A line starting with // is a comment: a note to yourself that is ignored. Comments are not saved in the form, so they are gone once you press To text or reopen the form.
  • Applying replaces every field row with the text. If you want to keep a field, keep its line.
  • Labels must be different from each other, because totals and groups find fields by label. The one exception is fields on pages nobody visits together, which may share a name. See Same name, separate columns below.
  • A group can run over several lines: keep going until its closing }.
  • The --- lines at the very top are form info, not a divider. The divider is .divider.
  • Tab does not exist on a phone keyboard. After picking a type from the menu on a phone, edit the sample line by hand.
  • On a computer, type .radio and the full sample line appears. Press Tab to select the label, and Tab again to select the choices.