Understanding the Item Definition Structure

Data API contains an Item definition structure - a clean and consistent format for specifying the layout of Questions and Features within an Item. The Item definition makes it easy to create, import and update Items with advanced layouts via Data API. Single column and side-by-side layouts as well as tabs and scrolling panels can all be created programmatically using the expressive definition structure.

Author API v1 and Data API v1 both use the same Item definition, so your Items are fully interoperable whether you bulk upload them or use the authoring tools.

The Item definition determines the Item's layout everywhere it is rendered to a user: in an Items API Activity, in Author API, or in Reports API, on desktop, tablet and mobile.

The Item definition is stored in the definition property against the Item. The definition is returned with all Items retrieved from Data API v1's itembank/items endpoint . You must specify an Item definition when you create or update Items via Data API v1.

The Item definition is specified as one or more nested objects, representing regions and a list of Widgets (Questions and/or Features) they contain. Here's a sample Item demonstrating the simplest kind of Item definition - a single root region and a list of Widgets. The two Widgets will be rendered in a single column layout, in the same order they appear in the array.

{
    "reference": "5b8b9d40-f03b-4df3-b276-84eef5580431",
    "status": "unpublished",
    "definition": {
        "widgets": [
            {
                "reference": "1a52f377-0db1-4aed-818c-866f684bb088"
            },
            {
                "reference": "2b21eca6-37af-4272-950a-fd9c472b2290"
            }
        ]
    },
    "questions": [
        {
            "reference": "2b21eca6-37af-4272-950a-fd9c472b2290",
            "type": "clozeassociation"
        }
    ],
    "features": [
        {
            "reference": "1a52f377-0db1-4aed-818c-866f684bb088",
            "type": "sharedpassage"
        }
    ]
}

There are different types of regions to support more complex layouts. The currently supported region types are root, column and tab. Each region type may contain either:

  • A set of Widgets (rendered vertically in a root, column or tab region); OR
  • A set of nested regions, which must all share the same type. Use multiple layers of nesting to achieve combinations of columns and tabs.

The following sections cover the usage and behaviour of the different region types.

{
    "regions": [],
    "widgets": [
        {
            "reference": "widget_reference_1"
        },
        {
            "reference": "widget_reference_2"
        }
    ],
    "vertical_divider": false,
    "scroll": {
        "enabled": false
    }
}

The root region is always at the top level of the Item definition. Its rendering behaviour is designed to easily accommodate the most common Item layouts:

  • If the widgets array is specified, those Widgets will be rendered in a single vertical column, in the same order they are listed in the array.
  • If the regions array is specified as a list of column regions, the columns are rendered side-by-side.
  • If the regions array is specified as a list of tab regions, the tabs will occupy the full width and height of the Item.

Note: either widgets or regions MUST be defined at the root level.

The vertical_divider and scroll properties can only be set on the root region. They globally determine the behaviour for all regions on the Item.

Property Type Description
type `"root"` Required: false
Default: "root"
regions array of Region objects

Nested column or tab regions. The given Region objects must all share the same type.

Required: false, unless "Widgets" is not defined

Widgets array of IncludedWidget objects

Each IncludedWidget object contains a reference property indicating the reference of the Widget to include. Widgets are rendered in a vertical stack, in the same order they appear in the widgets array.

Required: false, unless "regions" is not defined

vertical_divider boolean

Specify true to render a vertical divider between all column regions in the Item. Enabling this option on the root region affects all descendent regions.

Required: false
Default: false

scroll ScrollOptions object

If specified, the ScrollOptions has a single property as follows:{"enabled": true}

Specify "enabled": true to enable scrolling on all regions in the Item. If the content of a region is taller than the height allocated for the Item, the region will become a scrollable panel.

Omit the scroll property (or specify"enabled": false ) to force the Item to expand to accommodate the full height of the content.

Required: false

{
    "type": "column",
    "regions": [],
    "widgets": [
        {
            "reference": "widget_reference_1"
        },
        {
            "reference": "widget_reference_2"
        }
    ],
    "width": 50
}

Column regions subdivide their parent region into a set of side-by-side columns. Any parent region may contain either 1 or 2 columns. Widgets included in a column region will be rendered in a vertical stack, in the same order they appear in the widgets array.

Property Type Description
type "column" Required: true
regions array of Region objects

Nested column or tab regions. The given Region objects must all share the same type.

Required: false

widgets array of IncludedWidget objects

Each IncludedWidget object contains a reference property indicating the reference of the Widget to include. Widgets are rendered in a vertical stack, in the same order they appear in the widgets array.

Required: false

width int

Controls the width of this column, as a percentage of the width of the parent region. Allowed values are 50, 30, 40, 60, 70, 100. The width value of sibling columns must sum to 100.

Required: false
Default: 100

A tabs region acts as a required wrapper for grouping tabs - individual tabs will render standalone without this defined parent. The wrapper will occupy the full width and height of the parent region, and will provide the navigation element for displaying tabs.

{
    "type": "tabs",
    "regions": [
        {
            "type": "tab",
            ...
        },
        {
            "type": "tab",
            ...
        }
    ]
}
Property Type Description
type "tabs" Required: true
regions array of Region objects

Nested column or tab regions. The given Region objects must all share the same type.

Required: true

{
    "type": "tab",
    "label": "tab-1",
    "regions": [],
    "widgets": [
        {
            "reference": "widget_reference_1"
        },
        {
            "reference": "widget_reference_2"
        }
    ]
}

All sibling tab regions will be rendered as a set of tabs within their parent region. The set of tabs will occupy the full width and height of their parent region. Widgets included in a tab region will be rendered as a vertical stack within the tab's panel.

Property Type Description
type "tab" Required: true
label string

Label to be displayed for this tab.

Required: true

regions array of Region objects

Nested column or tab regions. The given Region objects must all share the same type.

Required: false

widgets array of IncludedWidget objects

Each IncludedWidget object contains a reference property indicating the reference of the Widget to include. Widgets are rendered in a vertical stack, in the same order they appear in the widgets array.

Required: false

{
    "regions": [
        {
            "type": "column",
            "width": 70,
            "widgets": [
                {
                    "reference": "widget_reference_1"
                }
            ]
        },
        {
            "type": "column",
            "width": 30,
            "widgets": [
                {
                    "reference": "widget_reference_2"
                }
            ]
        }
    ]
}
{
    "type": "tabs",
    "regions": [
        {
            "type": "tab",
            "label": "Tab 1",
            "widgets": [
                {
                    "reference": "widget_reference_1"
                }
            ]
        },
        {
            "type": "tab",
            "label": "Tab 2",
            "widgets": [
                {
                    "reference": "widget_reference_2"
                }
            ]
        }
    ]
}
{
    "regions": [
        {
            "type": "column",
            "width": 60,
            "regions": [
                {
                    "type": "tabs",
                    "regions": [
                        {
                            "type": "tab",
                            "label": "Tab 1",
                            "widgets": [
                                {
                                    "reference": "widget_reference_1"
                                }
                            ]
                        },
                        {
                            "type": "tab",
                            "label": "Tab 2",
                            "widgets": [
                                {
                                    "reference": "widget_reference_2"
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "type": "column",
            "width": 40,
            "widgets": [
                {
                    "reference": "widget_reference_3"
                }
            ]
        }
    ]
}

Dynamic content in the Item

Dynamic Content lets a single Question definition serve many variations, by pulling values from a data table into the Question's formula, response, and validation fields at render time. See What is Dynamic Content? and Setting Up a Data Table and Inserting Dynamic Content into a Question for the authoring-interface (CSV paste) workflow.

The same data table can also be created or updated programmatically, via the dynamic_content_data property on an Item, when using the Data API v1's Set Items endpoint. This lets you bulk-import Items and Questions together with their dynamic content data in a single request, instead of creating or pasting a CSV into each Item individually through Author API.

dynamic_content_data is a sibling property to definition on the Item object - it is not part of the layout structure, but travels with the Item in the same way questions and features do.

{
    "reference": "math_question_operands",
    "status": "unpublished",
    "definition": {
        "widgets": [
            {
                "reference": "operand_question_1"
            }
        ]
    },
    "questions": [
        {
            "reference": "operand_question_1",
            "type": "formulaV2"
        }
    ],
    "dynamic_content_data": {
        "cols": [
            "operand1",
            "operand2",
            "sum"
        ],
        "rows": {
            "1ba3db0c-4c51-4dd7-a610-18048fffda50": {
                "values": [
                    "4",
                    "8",
                    "12"
                ],
                "index": 0
            },
            "dd9d49fc-7e0b-4f12-9d2f-4d5b63893db0": {
                "values": [
                    "6",
                    "9",
                    "15"
                ],
                "index": 1
            },
            "fa9d76sw-7e0b-4f12-9f2f-4d5b85305jd3": {
                "values": [
                    "12",
                    "3",
                    "15"
                ],
                "index": 2
            }
        }
    }
}
Property Type Description
cols array of strings Required: true
The column headers of the data table, in display order. Each entry becomes a table variable name that can be referenced from the Question's formula, response, or validation fields (for example, {{operand1}}). The number and order of entries in cols defines the number and order of entries expected in every row's values array.
rows object Required: true
A map of individual data table rows, keyed by a unique row reference (a UUID). Each key represents one row - equivalent to one row of the CSV you would otherwise paste into the Author Site.
rows{row_reference} string (UUID) Required: true
A unique identifier for the row. This can be generated by you (e.g., when converting from CSV/spreadsheet source data) and is used to identify the row for future updates; it is not displayed to the learner.
rows{row_reference}.values array of strings Required: true
The cell values for this row, positionally matched to the cols array, i.e., values[0] corresponds to cols[0], values[1] to cols[1], and so on. The array must contain exactly as many entries as cols, in the same order.
rows{row_reference}.index integer Required: true
The zero-based display/preview order of this row relative to other rows in the table.

Important: Every entry in a row's values array must be a string, even if it represents a number. Unquoted or non-string values can cause the content engine to bind the wrong column to the Question at render/preview time.

// Correct — every value is a quoted string
"values": ["4", "8", "12"]

// Avoid — unquoted/non-string values can cause column mismatches
"values": [4, 8, 12]

If converting from CSV or a spreadsheet as part of a bulk import script, ensure your conversion step casts every cell value to a string before writing it into values, correctly handling any source values that use quote-wrapping to protect internal commas (for example, 10,000).

Note: Data API v1 recommends a limit of 20 columns and 50 rows per data table.

Was this article helpful?

Did you arrive here by accident? If so, learn more about Learnosity.