-
Notifications
You must be signed in to change notification settings - Fork 6
Temp cardscript readme
The goal of Cardscript is to provide a JSON-based language to describe User Interfaces (especially those which form part of a digital service).
Get hands-on with Cardscript using the online Cardscript Playpen!
- For some introductory context around why we developed Cardscript, please see Appendix A: Cardscript Motivation.
- A JSON Schema (Draft-07) for Cardscript is available here.
- The Cardscript Lerna multi-package repository (developed in the open on Github) provides several utilities to help work with the language. Please see Appendix B: Cardscript Utilities for further information.
In Cardscript, a card is represented by a JSON Object.
The content of a card is specified by configuring one-or-more elements, which are represented by JSON objects.
- In this example, a card is defined that contains two elements, one that defines a suitable
Jumbotron
(with some text and an accompanying image), followed by a secondInput.Text
-element for letting the user enter their name.
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Container",
"items": [
{
"type": "Jumbotron",
"backgroundImage": "wmfs/happy-people.jpg",
"title": "Register!",
"subtitle": "Let's get to know each other a bit better...",
"wash": "black"
},
{
"type": "TextBlock",
"text": "Name",
"wrap": true,
"separator": true
},
{
"type": "Input.Text",
"id": "name",
"placeholder": "e.g. Lucy Smith"
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
]
}
Cardscript is built on a handful of key concepts...
The purpose of Cardscript is to define a user interface, referred to as a "card".
- With Cardscript it's possible to configure a card with structure, validation, conditional content, dynamic values and context-sensitive behaviours (e.g. operating differently with an internet connection as opposed to without).
- Cardscript definitions are naturally stored in
.json
files (typically one-file-per-view). - In certain situations YAML (itself just a superset of JSON) may offer an interesting alternative to serialising Cardscript definitions (the cardscript-parser utility supports both)..
- Please note that a JSON Schema is available here, which may be used to validate the basic integrity of Cardscript content.
- For more comprehensive Cardscript validation, please refer to the cardscript-schema package.
Views defined in Cardscript may be rendered and executed by software. In this document, such software is referred to an "app".
- Apps can be implemented in any frontend-framework, language or library.
- Cardscript does not impose any aesthetic or UI constraints onto apps which implement it.
- Cardscript content can be embedded inside apps with GUI, CLI and even Voice-User interfaces.
- Please note several utilities are available to help embed Cardscript into apps. Please see Appendix B: Cardscript Utilities for further information.
Cards are constructed from an ordered list of "elements".
- To avoid overloading frontend-terms like 'component', Cardscript refers to each object in the
elements
array as an element. - Consider an element as an area of a view responsible for a particular task: either collecting a specific piece of information from a user or visualising some data.
- As such, elements can be interactive (
Input.Text
,Input.Number
, etc.) and non-interactive (Jumbotron
,Media
etc.) - The order that
Element
objects appear within a view definition is important - representing the order users will encounter them. - Cardscript is a delightful walled-garden, offering a fixed set of 46 p re-configured elements. If you need another element-type or an extra attribute... pull requests are very welcome! 😊
Ahead of the Reference section, here's a quick summary of the 46 elements supported in Cardscript 0.0.6
:
Element Type | Description |
---|---|
Action.Cancel |
Allows to cancel out of a form. |
Action.OpenUrl |
When invoked, show the given url either by launching it in an external web browser or showing in-situ with embedded web browser. |
Action.Save |
Allows to save a form to continue later. |
Action.ShowCard |
Defines an AdaptiveCard which is shown to the user when the button or link is clicked. |
Action.Submit |
Gathers input fields, merges with optional data field, and sends an event to the client. It is up to the client to determine how this data is processed. For example: With BotFramework bots, the client would send an activity through the messaging medium to the bot. |
ActionSet |
ActionSet allows actions to be displayed within a card. |
AdaptiveCard |
Root element in an Adaptive Card. |
AddressBlock |
Displays an address. |
CardList |
A container which opens a modal when clicked on to show a card. |
Chip |
A chip to display some text. |
Collapsible |
A container which expands when clicked on to show a card. |
Column |
Defines a container that is part of a ColumnSet. |
ColumnSet |
ColumnSet divides a region into Columns, allowing elements to sit side-by-side. |
Container |
Containers group items together. |
Fact |
Describes a Fact in a FactSet as a key/value pair. |
FactSet |
The FactSet element displays a series of facts (i.e. name/value pairs) in a tabular form. |
Image |
Displays an image. |
ImageSet |
The ImageSet displays a collection of Images similar to a gallery. |
Input.Address |
Lets a user enter an address. |
Input.ApiLookup |
Lets a user look up a value via an API. |
Input.Choice |
Describes a choice for use in a ChoiceSet. |
Input.ChoiceSet |
Allows a user to input a Choice. |
Input.Currency |
Lets a user enter a currency value. |
Input.Date |
Lets a user choose a date. |
Input.DateTime |
Lets a user enter a telephone number. |
Input.Email |
Lets a user enter an email. |
Input.FileUpload |
Lets a user upload a file. |
Input.Gender |
Lets a user enter a gender. |
Input.Name |
Lets a user enter a name. |
Input.Number |
Allows a user to enter a number. |
Input.Signature |
Lets a user enter a signature. |
Input.Slider |
Lets a user enter value with a slider. |
Input.TelephoneNumber |
Lets a user enter a telephone number. |
Input.Text |
Lets a user enter text. |
Input.Time |
Lets a user select a time. |
Input.Toggle |
Lets a user choose between two options. |
Jumbotron |
An element typically placed at the top of a card to describe its purpose. |
Map |
Displays a map. |
Media |
Displays a media player for audio or video content. |
MediaSource |
Defines a source for a Media element |
PhaseBanner |
Displays a banner highlighting a phase. |
Separator |
Displays a horizontal line. |
Tab |
Defines a container that is part of a TabSet. |
TabSet |
TabSet allows to display content through various tabs. |
Table |
Displays text, allowing control over font sizes, weight, and color. |
TextBlock |
Displays text, allowing control over font sizes, weight, and color. |
All the elements that define a view's content are specified in a simple array. This design helps align Cardscript with vertical-scrolling interfaces with very little friction. To assist with navigation (especially around larger, more complex content) it might be useful to split a view into more manageable pieces.
- In Cardscript, containers allow elements to be grouped into related chunks.
Example JSON
{
"title": "Simple set demo!",
"widgets": [
{
"type": "set",
"attributes": {
"tocTitle": "Profile"
}
},
{
"id": "name",
"type": "text",
"attributes": {
"heading": "Name",
"placeholder": "e.g. Lucy Smith",
"mandatory": true,
"minCharacters": 1,
"maxCharacters": 100,
"help": "Enter your full name here"
}
},
{
"type": "endSet"
}
]
}
- In this example, we are declaring that a
text
element (with the idname
) should be rendered within a container (which should appear in a Table of Contents with the heading "Profile"). - The beginning of each container is marked with a
container
element. - Nesting of containers is possible and containers are especially powerful when combined with dynamic expressions to conditionally show/hide content.
- Containers also enable apps to offer progress tracking functionality.
- Multi-step "wizard" interfaces are also easily achieved via containers.
- The
CardList
element uses exactly the same technique to define repeating-groups of elements.
Cardscript uses expressions to deliver dynamic content. Expressions are used to:
- Conditionally show/hide elements depending on values as they change.
- Validate card content based on more complex business rules.
- Affect the contents of enumerated lists.
- Default dynamic values.
- Calculate running totals, real-time summaries etc.
Consider an expression to be something that could be evaluated in a Javascript if (...) {}
statement.
{
"type": "AdaptiveCard",
"body": [
{
"type": "Jumbotron",
"backgroundImage": "wmfs/happy-people.jpg",
"title": "All done!",
"subtitle": "We're all done here, we would really appreciate some feedback though!",
"wash": "black"
},
{
"spacing": "large",
"id": "userWantsToGiveFeedback",
"type": "Input.Toggle",
"title": "I would like to leave some feedback"
},
{
"spacing": "large",
"id": "feedback",
"showWhen": "data.userWantsToGiveFeedback === true",
"type": "Input.Text",
"isMultiline": "true",
"placeholder": "Feedback"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
In the example above we have three elements:
- The first element is a simple
jumbotron
. - The second element is a simple boolean on/off
Input.Toggle
(with theid
ofuserWantsToGiveFeedback
) which is by default set tofalse
. - The third element is an
Input.Text
box (with theid
offeedback
) for collecting feedback from the user.
The feedback
element should only show if the userWantsToGiveFeedback
toggle is thrown on (i.e. true
).
There are a few new things going on here.
Most types of element (here the Toggle
and Input.Text
types) expect an app to read and write their values to an underlying data
object (using their respective id
values as keys).
It is also expected that any app implementing Cardscript should also make this data
object available within a safe sandbox while evaluating expressions.
In the previous example we can see the showWhen
attribute is being used on the feedback
element. The string value here is an expression, which will control the visibility of the element (i.e. it should only be shown to the user when the expression evaluates to true
).
Apps must ensure expressions are evaluated in a safe sandbox context. As such only certain objects may be referred to within an expression:
Sandbox object | Description |
---|---|
data |
The current card data being stored. Should be kept fresh in real-time using UI binding techniques. |
env |
Some environmental information, e.g. the user's name, if the app has access to an internet connection etc. |
Apps are expected to provide the following details via an env
object when evaluating expressions:
Property | Type | Description |
---|---|---|
username |
string |
Username of the the user currently using the form. |
startedOffline |
boolean |
Indicates if the form was started online, or not. |
Cardscript 0.0.6
supports a set of 46 common attributes from which elements can be configured.
Not one element-type requires all these attributes. Attributes are often optional and some element-types don't need an attributes
object at all.
Element Name | Type | Description |
---|---|---|
Action.Cancel |
object |
Allows to cancel out of a form. |
Action.OpenUrl |
object |
When invoked, show the given url either by launching it in an external web browser or showing in-situ with embedded web browser. |
Action.Save |
object |
Allows to save a form to continue later. |
Action.ShowCard |
object |
Defines an AdaptiveCard which is shown to the user when the button or link is clicked. |
Action.Submit |
object |
Gathers input fields, merges with optional data field, and sends an event to the client. It is up to the client to determine how this data is processed. For example: With BotFramework bots, the client would send an activity through the messaging medium to the bot. |
ActionSet |
object |
ActionSet allows actions to be displayed within a card. |
AdaptiveCard |
object |
Root element in an Adaptive Card. |
AddressBlock |
object |
Displays an address. |
CardList |
object |
A container which opens a modal when clicked on to show a card. |
Chip |
object |
A chip to display some text. |
Collapsible |
object |
A container which expands when clicked on to show a card. |
Column |
object |
Defines a container that is part of a ColumnSet. |
ColumnSet |
object |
ColumnSet divides a region into Columns, allowing elements to sit side-by-side. |
Container |
object |
Containers group items together. |
Fact |
object |
Describes a Fact in a FactSet as a key/value pair. |
FactSet |
object |
The FactSet element displays a series of facts (i.e. name/value pairs) in a tabular form. |
Image |
object |
Displays an image. |
ImageSet |
object |
The ImageSet displays a collection of Images similar to a gallery. |
Input.Address |
object |
Lets a user enter an address. |
Input.ApiLookup |
object |
Lets a user look up a value via an API. |
Input.Choice |
object |
Describes a choice for use in a ChoiceSet. |
Input.ChoiceSet |
object |
Allows a user to input a Choice. |
Input.Currency |
object |
Lets a user enter a currency value. |
Input.Date |
object |
Lets a user choose a date. |
Input.DateTime |
object |
Lets a user enter a telephone number. |
Input.Email |
object |
Lets a user enter an email. |
Input.FileUpload |
object |
Lets a user upload a file. |
Input.Gender |
object |
Lets a user enter a gender. |
Input.Name |
object |
Lets a user enter a name. |
Input.Number |
object |
Allows a user to enter a number. |
Input.Signature |
object |
Lets a user enter a signature. |
Input.Slider |
object |
Lets a user enter value with a slider. |
Input.TelephoneNumber |
object |
Lets a user enter a telephone number. |
Input.Text |
object |
Lets a user enter text. |
Input.Time |
object |
Lets a user select a time. |
Input.Toggle |
object |
Lets a user choose between two options. |
Jumbotron |
object |
An element typically placed at the top of a card to describe its purpose. |
Map |
object |
Displays a map. |
Media |
object |
Displays a media player for audio or video content. |
MediaSource |
object |
Defines a source for a Media element |
PhaseBanner |
object |
Displays a banner highlighting a phase. |
Separator |
object |
Displays a horizontal line. |
Tab |
object |
Defines a container that is part of a TabSet. |
TabSet |
object |
TabSet allows to display content through various tabs. |
Table |
object |
Displays text, allowing control over font sizes, weight, and color. |
TextBlock |
object |
Displays text, allowing control over font sizes, weight, and color. |
Here is the full list of all 46 elements supported in Cardscript 0.0.6
(please see Element summary for a handy index).
Allows to cancel out of a form.
Example JSON
{
"type": "Action.Cancel",
"title": "Cancel"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Action.Cancel" . |
title |
string | Optional |
Label for button or link that represents this action. |
iconUrl |
string | Optional |
Optional icon to be shown on the action in conjunction with the title |
When invoked, show the given url either by launching it in an external web browser or showing in-situ with embedded web browser.
Example JSON
{
"type": "Action.OpenUrl",
"title": "Open Url",
"url": "https://github.com/wmfs/cardscript"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Action.OpenUrl" . |
title |
string | Optional |
Label for button or link that represents this action. |
iconUrl |
string | Optional |
Optional icon to be shown on the action in conjunction with the title |
url |
string | Required |
The URL to open. |
Allows to save a form to continue later.
Example JSON
{
"type": "Action.Save",
"title": "Save"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Action.Save" . |
title |
string | Optional |
Label for button or link that represents this action. |
iconUrl |
string | Optional |
Optional icon to be shown on the action in conjunction with the title |
Defines an AdaptiveCard which is shown to the user when the button or link is clicked.
Example JSON
{
"type": "Action.ShowCard",
"title": "Action.ShowCard",
"card": {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "What do you think?"
},
{
"id": "opinion",
"type": "Input.Text",
"spacing": "large",
"default": "Amazing!"
}
]
}
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Action.ShowCard" . |
title |
string | Optional |
Label for button or link that represents this action. |
iconUrl |
string | Optional |
Optional icon to be shown on the action in conjunction with the title |
card |
Required |
Gathers input fields, merges with optional data field, and sends an event to the client. It is up to the client to determine how this data is processed. For example: With BotFramework bots, the client would send an activity through the messaging medium to the bot.
Example JSON
{
"type": "Action.Submit",
"title": "Submit",
"data": {
"x": "y"
}
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Action.Submit" . |
title |
string | Optional |
Label for button or link that represents this action. |
iconUrl |
string | Optional |
Optional icon to be shown on the action in conjunction with the title |
data |
string,object | Optional |
Initial data that input fields will be combined with. These are essentially 'hidden' properties. |
ActionSet allows actions to be displayed within a card.
Example JSON
{
"type": "ActionSet",
"spacing": "large",
"actions": [
{
"type": "Action.OpenUrl",
"title": "Open Url",
"url": "https://github.com/wmfs/cardscript"
},
{
"type": "Action.Submit",
"title": "Submit",
"data": {
"x": "y"
}
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "ActionSet" . |
actions |
Required |
The Actions to show in the card's action bar. | |
spacing |
Optional |
Root element in an Adaptive Card.
Example JSON
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Container",
"items": [
{
"type": "Jumbotron",
"backgroundImage": "wmfs/happy-people.jpg",
"title": "Register!",
"subtitle": "Let's get to know each other a bit better...",
"wash": "black"
},
{
"type": "TextBlock",
"text": "Name",
"wrap": true,
"separator": true
},
{
"type": "Input.Text",
"id": "name",
"placeholder": "e.g. Lucy Smith"
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "AdaptiveCard" . |
actions |
Optional |
The Actions to show in the card's action bar. | |
body |
Optional |
The card elements to show in the primary card region. | |
selectAction |
object | Optional |
An Action that will be invoked when the card is tapped or selected. Action.ShowCard is not supported. |
Displays an address.
Example JSON
{
"type": "AddressBlock",
"dataPath": "addressBlock"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "AddressBlock" . |
title |
string | Optional |
Title of the AddressBlock. |
dataPath |
string | Required |
Points to the holding the address. |
multiline |
boolean | Optional |
Wether the address in multiple lines. |
lineDelimited |
string | Optional |
The string of character(s) which the address is delimited by. |
A container which opens a modal when clicked on to show a card.
Example JSON
{
"id": "cardList",
"type": "CardList",
"editable": true,
"instanceTitleTemplate": "You thought: '{{item.opinion}}'.",
"addButtonLabel": "Click me!",
"card": {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "What do you think?"
},
{
"id": "opinion",
"type": "Input.Text",
"spacing": "large",
"value": "Amazing!"
}
]
}
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
A unique identifier associated with the element. |
type |
string | Required |
Must be "CardList" . |
addButtonLabel |
string | Optional |
Text to be displayed as label of button. |
card |
Required |
||
instanceTitleTemplate |
string | Optional |
A handlebars-like template for conjuring a title per instance. |
instanceSubtitleTemplate |
string | Optional |
A handlebars-like template for conjuring a subtitle per instance. |
editable |
boolean | Optional |
The CardList element can either act as a modal to display a block of Card Elements or as a form which can be completed and pushed to an array. |
A chip to display some text.
Example JSON
{
"type": "Chip",
"text": "Example",
"color": "good"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Chip" . |
text |
string | Required |
Text to be displayed in chip. |
color |
string | Optional |
Color of the chip |
A container which expands when clicked on to show a card.
Example JSON
{
"type": "Collapsible",
"title": "Click me!",
"card": {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "Hello!"
}
]
}
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Collapsible" . |
title |
string | Required |
Text to be displayed as label. |
card |
Required |
Defines a container that is part of a ColumnSet.
Example JSON
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"text": "col-1"
},
{
"type": "TextBlock",
"text": "col-1"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
items |
Required |
The card elements to include in the Column . |
|
selectAction |
object | Optional |
An Action that will be invoked when the Column is tapped or selected. Action.ShowCard is not supported. |
style |
string | Optional |
Style hint for Column . |
width |
string,number | Optional |
"auto" , "stretch" , or a number representing relative width of the column in the column group. |
type |
string | Optional |
Must be "Column" . |
ColumnSet divides a region into Columns, allowing elements to sit side-by-side.
Example JSON
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"text": "col-1"
},
{
"type": "TextBlock",
"text": "col-1"
}
]
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"text": "col-2"
}
]
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
columns |
array | Optional |
The array of Columns to divide the region into. |
selectAction |
object | Optional |
An Action that will be invoked when the ColumnSet is tapped or selected. Action.ShowCard is not supported. |
type |
string | Required |
Must be "ColumnSet" . |
Containers group items together.
Example JSON
{
"type": "Container",
"color": "accent",
"spacing": "large",
"items": [
{
"type": "TextBlock",
"text": "Accent!"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Container" . |
color |
string | Optional |
Controls the color of the Container. |
items |
Required |
The card elements to render inside the Container . |
|
selectAction |
object | Optional |
An Action that will be invoked when the Container is tapped or selected. Action.ShowCard is not supported. |
style |
string | Optional |
Style hint for Container . |
verticalContentAlignment |
string | Optional |
Defines how the content should be aligned vertically within the container. |
Describes a Fact in a FactSet as a key/value pair.
Example JSON
{
"title": "Hello:",
"value": "World"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Optional |
|
title |
string | Required |
The title of the fact. |
value |
string | Required |
The value of the fact. |
The FactSet element displays a series of facts (i.e. name/value pairs) in a tabular form.
Example JSON
{
"type": "FactSet",
"facts": [
{
"title": "Hello:",
"value": "World"
},
{
"title": "HELLO:",
"value": "WORLD"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
facts |
array | Required |
The array of Fact s. |
type |
string | Required |
Must be "FactSet" . |
Displays an image.
Example JSON
{
"type": "Image",
"url": "https://tymly.io/wp-content/uploads/2017/11/logo-tymly-main-colour.png",
"size": "large",
"horizontalAlignment": "left"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
altText |
string | Optional |
Alternate text describing the image. |
horizontalAlignment |
Optional |
||
selectAction |
object | Optional |
An Action that will be invoked when the Image is tapped or selected. Action.ShowCard is not supported. |
size |
Optional |
||
style |
Optional |
||
type |
string | Required |
Must be "Image" . |
url |
string | Required |
The URL to the image. |
The ImageSet displays a collection of Images similar to a gallery.
Example JSON
{
"type": "ImageSet",
"images": [
{
"type": "Image",
"url": "https://tymly.io/wp-content/uploads/2017/11/logo-tymly-main-colour.png",
"size": "medium"
},
{
"type": "Image",
"url": "https://tymly.io/wp-content/uploads/2017/11/logo-tymly-main-colour.png",
"size": "medium"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
images |
array | Required |
The array of Image elements to show. |
imageSize |
Optional |
||
type |
string | Required |
Must be "ImageSet" . |
Lets a user enter an address.
Example JSON
{
"id": "inputAddress",
"type": "Input.Address"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Address" . |
Lets a user look up a value via an API.
Example JSON
{
"id": "inputApiLookup",
"type": "Input.ApiLookup"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.ApiLookup" . |
Describes a choice for use in a ChoiceSet.
Example JSON
{
"title": "Choice 1",
"value": "CHOICE_1"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Optional |
|
title |
string | Required |
Text to display. |
value |
string | Required |
The raw value for the choice. NOTE: do not use a , in the value, since a ChoiceSet with isMultiSelect set to true returns a comma-delimited string of choice values. |
Allows a user to input a Choice.
Example JSON
{
"type": "Input.ChoiceSet",
"id": "choice",
"spacing": "medium",
"value": "CHOICE_1",
"choices": [
{
"title": "Choice 1",
"value": "CHOICE_1"
},
{
"title": "Choice 2",
"value": "CHOICE_2"
},
{
"title": "Choice 3",
"value": "CHOICE_3"
}
],
"style": "expanded"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
choices |
array | Required |
Choice options. |
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
isMultiSelect |
boolean | Optional |
Allow multiple choices to be selected. |
style |
Optional |
||
type |
string | Required |
Must be "Input.ChoiceInput" . |
value |
string | Optional |
The initial choice (or set of choices) that should be selected. For multi-select, specify a comma-separated string of values. |
Lets a user enter a currency value.
Example JSON
{
"id": "currency",
"type": "Input.Currency",
"placeholder": "Input.Currency",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Currency" . |
placeholder |
string | Optional |
Description of the input desired. Displayed when no text has been input. |
max |
number | Optional |
Hint of maximum value (may be ignored by some clients). |
min |
number | Optional |
Hint of minimum value (may be ignored by some clients). |
Lets a user choose a date.
Example JSON
{
"id": "date",
"type": "Input.Date",
"placeholder": "Input.Date",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
max |
string | Optional |
Hint of maximum value expressed in ISO-8601 format (may be ignored by some clients). |
min |
string | Optional |
Hint of minimum value expressed in ISO-8601 format (may be ignored by some clients). |
placeholder |
string | Optional |
Description of the input desired. Displayed when no selection has been made. |
type |
string | Required |
Must be "Input.Date" . |
value |
string | Optional |
The initial value for this field expressed in ISO-8601 format. |
Lets a user enter a telephone number.
Example JSON
{
"id": "date",
"type": "Input.DateTime",
"placeholder": "Input.DateTime",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.DateTime" . |
placeholder |
string | Optional |
Description of the input desired. Displayed when no text has been input. |
Lets a user enter an email.
Example JSON
{
"id": "email",
"type": "Input.Email",
"placeholder": "Input.Email",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Email" . |
placeholder |
string | Optional |
Description of the input desired. Displayed when no text has been input. |
Lets a user upload a file.
Example JSON
{
"type": "Input.FileUpload",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.FileUpload" . |
Lets a user enter a gender.
Example JSON
{
"id": "inputGender",
"type": "Input.Gender",
"preferNotToSay": true,
"preferToSelfDescribe": true,
"includeTransgender": true
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Gender" . |
term |
string | Optional |
Whether the gender or sex should be asked. |
preferNotToSay |
boolean | Optional |
Includes Prefer not to say gender in list. |
preferToSelfDescribe |
boolean | Optional |
Includes Prefer not to self describe gender in list. |
includeTransgender |
boolean | Optional |
Includes transgender in list. |
Lets a user enter a name.
Example JSON
{
"id": "name",
"type": "Input.Name",
"placeholder": "Input.Name",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Name" . |
Allows a user to enter a number.
Example JSON
{
"id": "number",
"type": "Input.Number",
"placeholder": "Input.Number",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
max |
number | Optional |
Hint of maximum value (may be ignored by some clients). |
min |
number | Optional |
Hint of minimum value (may be ignored by some clients). |
placeholder |
string | Optional |
Description of the input desired. Displayed when no selection has been made. |
type |
string | Required |
Must be "Input.Number" . |
value |
number | Optional |
Initial value for this field. |
Lets a user enter a signature.
Example JSON
{
"id": "inputSignature",
"type": "Input.Signature",
"agreement": "I agree that...",
"saveText": "Send",
"guidance": "Please enter your signature below..."
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Signature" . |
agreement |
string | Optional |
Agreement text to be displayed above the signature pad. |
saveText |
string | Optional |
Customise the text of the save button. |
guidance |
string | Optional |
Guidance text to be displayed with the signature button. |
Lets a user enter value with a slider.
Example JSON
{
"id": "slider",
"type": "Input.Slider",
"spacing": "medium",
"min": -20,
"max": 20,
"step": 4,
"value": 3
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.Slider" . |
min |
number | Optional |
Minimum value of the model. |
max |
number | Optional |
Maximum value of the model. |
step |
number | Optional |
Step amount between values. |
value |
string | Optional |
The initial value for this field. |
Lets a user enter a telephone number.
Example JSON
{
"id": "inputTelephoneNumber",
"type": "Input.TelephoneNumber",
"placeholder": "Input.TelephoneNumber",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
type |
string | Required |
Must be "Input.TelephoneNumber" . |
Lets a user enter text.
Example JSON
{
"id": "textEditor",
"type": "Input.Text",
"placeholder": "Input.Text",
"spacing": "medium",
"editor": true,
"value": "editor: true"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
isMultiline |
boolean | Optional |
If true , allow multiple lines of input. |
maxLength |
number | Optional |
Hint of maximum length characters to collect (may be ignored by some clients). |
placeholder |
string | Optional |
Description of the input desired. Displayed when no text has been input. |
style |
Optional |
||
type |
string | Required |
Must be "Input.Text" . |
value |
string | Optional |
The initial value for this field. |
editor |
boolean | Optional |
Whether the field should be a WYSIWYG (“what you see is what you get”) editor, if false then plain text field. |
Lets a user select a time.
Example JSON
{
"id": "time",
"type": "Input.Time",
"placeholder": "Input.Time",
"spacing": "medium"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
max |
string | Optional |
Hint of maximum value (may be ignored by some clients). |
min |
string | Optional |
Hint of minimum value (may be ignored by some clients). |
placeholder |
string | Optional |
Description of the input desired. Displayed when no time has been selected. |
type |
string | Required |
Must be "Input.Time" . |
value |
string | Optional |
The initial value for this field expressed in ISO-8601 format. |
Lets a user choose between two options.
Example JSON
{
"id": "toggle",
"type": "Input.Toggle",
"spacing": "medium",
"title": "Input.Toggle"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
id |
string | Required |
Unique identifier for the value. Used to identify collected input when the Submit action is performed. |
title |
string | Required |
Title for the toggle |
type |
string | Required |
Input.Toggle |
value |
string | Optional |
The current selected value. If the item is selected that "valueOn" will be used, otherwise "valueOff" |
valueOff |
string | Optional |
The value when toggle is off |
valueOn |
string | Optional |
The value when toggle is on |
An element typically placed at the top of a card to describe its purpose.
Example JSON
{
"type": "Jumbotron",
"backgroundImage": "wmfs/pizza.jpg",
"title": "Title",
"subtitle": "Subtitle",
"wash": "black"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Jumbotron" . |
title |
string | Required |
Text to be displayed as heading. |
subtitle |
string | Optional |
Text to be displayed as subheading. |
wash |
string | Optional |
Type of wash to have over the background. |
backgroundImage |
string | Optional |
Relative URL to image to be displayed as background. |
Displays a map.
Example JSON
{
"type": "Map"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Map" . |
Displays a media player for audio or video content.
Example JSON
{
"type": "Media",
"poster": "https://adaptivecards.io/content/poster-video.png",
"sources": [
{
"mimeType": "video/mp4",
"url": "https://adaptivecardsblob.blob.core.windows.net/assets/AdaptiveCardsOverviewVideo.mp4"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Media" . |
sources |
array | Optional |
Array of media sources to attempt to play. |
poster |
string | Optional |
URL of an image to display before playing. |
altText |
string | Optional |
Alternate text describing the audio or video. |
Defines a source for a Media element
Example JSON
{
"mimeType": "video/mp4",
"url": "https://adaptivecardsblob.blob.core.windows.net/assets/AdaptiveCardsOverviewVideo.mp4"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
mimeType |
string | Required |
Mime type of associated media (e.g. "video/mp4" ). |
url |
string | Required |
URL to media. |
Displays a banner highlighting a phase.
Example JSON
{
"type": "PhaseBanner",
"phase": "alpha"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "PhaseBanner" . |
phase |
string | Optional |
The phase which the service is in. |
Displays a horizontal line.
Example JSON
{
"type": "Separator"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Separator" . |
Defines a container that is part of a TabSet.
Example JSON
{
"type": "Tab",
"title": "Tab 1",
"items": [
{
"type": "TextBlock",
"text": "Tab 1 Content"
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Optional |
Must be "Tab" . |
items |
Required |
The card elements to include in the Tab . |
|
title |
string | Required |
The title of the Tab . |
TabSet allows to display content through various tabs.
Example JSON
{
"type": "TabSet",
"spacing": "large",
"tabs": [
{
"type": "Tab",
"title": "Tab 1",
"items": [
{
"type": "TextBlock",
"text": "Tab 1 Content"
}
]
},
{
"type": "Tab",
"title": "Tab 2",
"items": [
{
"type": "TextBlock",
"text": "Tab 2 Content"
}
]
}
]
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "TabSet" . |
tabs |
array | Optional |
The array of Tabs to divide content. |
Displays text, allowing control over font sizes, weight, and color.
Example JSON
{
"type": "Table",
"title": "Opinions (Add some via CardList example above to see them appear in Table here)",
"arrayPath": "cardList",
"columns": [
{
"title": "Opinion",
"field": "opinion"
}
],
"resultLimit": 5
}
Properties
Name | Type | Required | Description |
---|---|---|---|
type |
string | Required |
Must be "Table" . |
title |
string | Optional |
Title displayed for the Table . |
arrayPath |
string | Required |
Points to the array of data to be displayed. |
columns |
array | Required |
|
resultLimit |
integer | Optional |
Limit the results per page. |
Displays text, allowing control over font sizes, weight, and color.
Example JSON
{
"type": "TextBlock",
"text": "color: good",
"color": "good"
}
Properties
Name | Type | Required | Description |
---|---|---|---|
color |
string | Optional |
Controls the color of TextBlock elements. |
horizontalAlignment |
Optional |
||
isSubtle |
boolean | Optional |
If true , displays text slightly toned down to appear less prominent. |
maxLines |
number | Optional |
Specifies the maximum number of lines to display. |
size |
string | Optional |
Controls size of text. |
text |
string | Required |
Text to display. |
type |
string | Required |
Must be "TextBlock" . |
weight |
string | Optional |
Controls the weight of TextBlock elements. |
wrap |
boolean | Optional |
If true , allow text to wrap. Otherwise, text is clipped. |
The Cardscript specification and related tooling is provided under MIT.
Cardscript is the product of a small in-house development team at West Midlands Fire Service. Our work over the last 20 years has often involved collecting data from a variety of teams and environments. During this time, our best experiences have come from taking a declarative approach to defining form content.
-
Originally we used XML to define the content of our forms (or workbooks as they became known). From there it was a relatively simple process to write a renderer to conjure appropriate UIs from those definitions. Over the intervening years we have defined some 50 workbooks in XML to collect over 3 million documents and we've extended our DSL to support growing business need.
-
We're now actively working on our third-generation view rendering engine. While designing the accompanying backend, we've found great benefit in aligning to open standards (for example our workflow is now defined in Amazon State Language).
-
Given our positive experiences of declarative techniques and open standards, it was a natural evolution for our new declarative-UI engine to incorporate an open standard. We therefore prototyped using a few projects (for example Schema Form) and shipped our MVP using Mozilla React Schema Form.
They're great libraries and helped us get up-and-running quickly.
In hindsight, both these specifications are restricted by being bound to an underlying UI technology (i.e. Angular and React respectively). Both projects mandate a traditional web-form interface too. What if we're only working in a CLI context, or want to try some voice-interface technology? And what if we wanted to define dashboards and similar read-only content?
- React Schema Form and Schema.io work well for reasonably trivial UI content, but start adding requirements for expression-based conditionality/validation, different layout structures, differing online/offline behaviours etc. and we were soon "working against" both approaches - even to deliver quite basic experiences.
To compound matters, the underlying use of JSON Schema involves a lot of duplication and arbitrary splitting between model and UI definitions: which soon builds friction when describing larger UIs. In turn, we found this complexity bleeds into tooling and the wider architecture.
So with a shopping-list in-hand:
- Must be an open standard and encourage contributions
- Must be easily extended to include new capabilities
- Must not be tied to any particular frontend technology or project
- Must not be tied to a particular UI pattern
- Must use a standard expression language (strong preference towards Javascript)
- Must support complex validation expressions
- Must support dynamic show/hide expressions (with optimisation for large chunks of the view)
- Must support online/offline behaviours
- Must have a schema to validate declarations and support tooling
- Must have an open SDK or similar to assist implementation
- Must be well documented
- Must have minimum of friction for embedding in a variety of app styles
- Strong preference towards JSON-based languages
...we went looking for an open standard capable of replacing our existing library of XML-defined views (some of which are pretty hefty in terms of number of components and logic).
Spoiler: We couldn't find one. Which was disappointing (and unexpected), because the experience of adopting Amazon State Language had been great. We were edging closer to defining our own, but at the same time very mindful of this sort of thing:
-
A particularity bad smell came about when we developed a simple intermediary format (to ease tooling complexity and authoring processes) which we could translate back into React Schema Form definitions. It was becoming evident we didn't have a good fit for what we wanted to do, and that using a badly-fitting standard is actually worse than not using a standard at all.
-
The XML used in our outgoing generation had some problems: requiring it's own expression-language was a particular mis-step and XML feels ancient if used directly on the client app (especially in Single Page Applications and Progressive Web Apps contexts).
- It does all the things we need, and we think it might be useful to other organisations if it became a standard.
Here are some Node.js-based utilities to help working with Cardscript:
Package | Description | Github | NPM |
---|---|---|---|
cardscript-doc-generator |
Produces Cardscript's main README.md file using Cardscript's JSON Schema and other sources. | Here | Here |
cardscript-examples |
Example Cardscript JSON files, to help with testing and documentation. Includes loader utility. | Here | Here |
cardscript-cleaner |
Cleans Cardscript form data to ensure we only submit the data that we should. | Here | Here |
cardscript-extract-defaults |
Extracts sensible defaults from some Cardscript. | Here | Here |
cardscript-extract-lists |
Extracts list objects from some Cardscript. | Here | Here |
cardscript-parser |
Like JSON.parse(), but for Cardscript. And it supports YAML. | Here | Here |
cardscript-quasar-playpen |
Cardscript Playpen | Here | Here |
cardscript-schema |
Contains a JSON Schema for Cardscript, along with a validation utility. | Here | Here |
cardscript-table-of-contents |
Extracts a table-of-contents from some Cardscript. | Here | Here |
cardscript-to-quasar |
Produces a template for use with Quasar from some Cardscript. | Here | Here |
cardscript-to-vuelidate |
Takes in a Cardscript JSON object and attempts to extract validation schema from the widgets. | Here | Here |
cardscript-vue-sdk |
An SDK for using Cardscript with Vue/Vuetify | Here | Here |
@wmfs/json-schema-to-cardscript |
Scaffold Cardscript from a JSON-Schema schema | Here | Here |
react-jsonschema-form-to-cardscript |
Produces Cardscript converted from react-jsonschema-form file. | Here | Here |
@wmfs/tymly-cardscript-sdk |
Tymly Cardscript SDK | Here | Here |
tymly-cardscript-sdk-doc-generator |
Produces a README.md file for the tymly-cardscript-sdk package. | Here | Here |