This specification defines a new form encoding algorithm that enables the transmission of form data as JSON. Instead of capturing form data as essentially an array of key-value pairs which is the bread and butter of existing form encodings, it relies on a simple name attribute syntax that makes it possible to capture rich data structures as JSON directly.

Publication as a Working Group Note does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was published by the HTML Working Group as a Working Group Note. If you wish to make comments regarding this document, please send them to public-html@w3.org ( subscribe , archives ). All comments are welcome.

Beware. This specification is no longer in active maintenance and the HTML Working Group does not intend to maintain it further.

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

1. Introduction

This section is non-normative.

JSON is commonly used as an exchange format between Web client and backend services. Enabling HTML forms to submit JSON directly simplifies implementation as it enables backend services to operate by accepting a single input format that is what's more able to encode richer structure than other form encodings (where structure has traditional had to be emulated).

User agents that implement this specification will transmit JSON data from their forms whenever the form's enctype attribute is set to application/json . During the transition period, user agents that do not support this encoding will fall back to using application/x-www-form-urlencoded . This can be detected on the server side, and the conversion algorithm described in this specification can be used to convert such data to JSON.

The path format used in input name s is straightforward. To begin with, when no structuring information is present, the information will simply be captured as keys in a JSON object:

Example 1 : Basic Keys <form enctype = 'application/json' > <input name = 'name' value = 'Bender' > <select name = 'hind' > <option selected > Bitable </option> <option> Kickable </option> </select> <input type = 'checkbox' name = 'shiny' checked > </form> // produces { "name": "Bender" , "hind": "Bitable" , "shiny": true }

If a path is repeated, its value is captured as an array:

Example 2 : Multiple Values <form enctype = 'application/json' > <input type = 'number' name = 'bottle-on-wall' value = '1' > <input type = 'number' name = 'bottle-on-wall' value = '2' > <input type = 'number' name = 'bottle-on-wall' value = '3' > </form> // produces { "bottle-on-wall": [1, 2, 3] }

Deeper structures can be produced using sub-keys in the path, using either string keys for objects or integer keys for arrays:

Example 3 : Deeper Structure <form enctype = 'application/json' > <input name = 'pet[species]' value = 'Dahut' > <input name = 'pet[name]' value = 'Hypatia' > <input name = 'kids[1]' value = 'Thelma' > <input name = 'kids[0]' value = 'Ashley' > </form> // produces { "pet": { "species": "Dahut" , "name": "Hypatia" } , "kids": ["Ashley", "Thelma"] }

As you can see above, the keys for array values can be in any order. If the array is somehow sparse, then null values are inserted:

Example 4 : Sparse Arrays <form enctype = 'application/json' > <input name = 'hearbeat[0]' value = 'thunk' > <input name = 'hearbeat[2]' value = 'thunk' > </form> // produces { "hearbeat": ["thunk", null, "thunk"] }

Paths can cause structures to nest to arbitrary depths:

Example 5 : Even Deeper <form enctype = 'application/json' > <input name = 'pet[0][species]' value = 'Dahut' > <input name = 'pet[0][name]' value = 'Hypatia' > <input name = 'pet[1][species]' value = 'Felis Stultus' > <input name = 'pet[1][name]' value = 'Billie' > </form> // produces { "pet": [ { "species": "Dahut" , "name": "Hypatia" } , { "species": "Felis Stultus" , "name": "Billie" } ] }

Really, any depth you might need.

Example 6 : Such Deep <form enctype = 'application/json' > <input name = 'wow[such][deep][3][much][power][!]' value = 'Amaze' > </form> // produces { "wow": { "such": { "deep": [ null , null , null , { "much": { "power": { "!": "Amaze" } } } ] } } }

The algorithm does not lose data in that every piece of information ends up being submitted. But given the path syntax, it is possible to introduce clashes such that one may attempt to set an object, an array, and a scalar value on the same key.

As seen in a previous example, trying to set multiple scalars on the same key will convert the value into an array. Trying to set a scalar value at a path that also contains an object will cause the scalar to be set on that object with the empty string key. Trying to set an array value at a path that also contains an object will cause the non-null values of that array to be set on the object using their array indices as keys. This is exemplified below:

Example 7 : Merge Behaviour <form enctype = 'application/json' > <input name = 'mix' value = 'scalar' > <input name = 'mix[0]' value = 'array 1' > <input name = 'mix[2]' value = 'array 2' > <input name = 'mix[key]' value = 'key key' > <input name = 'mix[car]' value = 'car key' > </form> // produces { "mix": { "": "scalar" , "0": "array 1" , "2": "array 2" , "key": "key key" , "car": "car key" } }

This may seem somewhat convoluted but it should be considered as a resilience mechanism meant to ensure that data is not lost rather than the normal usage of the JSON encoding.

As we have seen above, multiple values with the same key are upgraded to an array, and it is also possible to directly use array offsets. However there are cases in which when generating a form from existing data, one may not know if there will be one or more instances of a given key (so that without using indices one will get back at times a scalar, at times an array) and it can be slightly cumbersome to properly generate array indices (especially if the field may be modified on the client side, which would mean maintaining array indices properly there). In order to indicate that a given path must contain an array irrespective of the number of its items, and without resorting to indices, one may use the append notation (only as the final step in a path):

Example 8 : Append <form enctype = 'application/json' > <input name = 'highlander[]' value = 'one' > </form> // produces { "highlander": ["one"] }

The JSON encoding also supports file uploads. The values of files are themselves structured as objects and contain a type field indicating the MIME type, a name field containing the file name, and a body field with the file's content as base64.

Example 9 : Files <form enctype = 'application/json' > <input type = 'file' name = 'file' multiple > </form> // assuming the user has selected two text files, produces: { "file": [ { "type": "text/plain", "name": "dahut.txt", "body": "REFBQUFBQUFIVVVVVVVVVVVVVCEhIQo=" }, { "type": "text/plain", "name": "litany.txt", "body": "SSBtdXN0IG5vdCBmZWFyLlxuRmVhciBpcyB0aGUgbWluZC1raWxsZXIuCg==" } ] }

Still in the spirit of not losing information, whenever a path makes use of an invalid syntax, it is simply used whole as if it were just a key with no structure: