A grid block's data needs a flat array of cells - two per row for a 2-column grid, and so on (see {overlay}.json's grid block for the full property reference). This page is about building that array from a repeating group.

No JS needed: bind directly

If every cell is just a sub-field's raw value, skip data and set source_field/column_keys on the block instead:

{ "id": "options_grid", "type": "grid", "columns": 2,
  "source_field": "options", "column_keys": ["description", "price"] }

The Overlay Editor's grid panel has a "Bind to Repeating Group" section that writes these same two properties.

With formatting: loop and push

The moment you need currency signs, right-aligned prices, or a header row, reach for data instead - a data set on the block ignores source_field/column_keys entirely:

inputs.gridData = [];
for (var i = 0; i < inputs.options.length; i++) {
  var o = inputs.options[i];
  inputs.gridData.push(
    { text: o.description },
    { text: '$' + o.price, 'text-align': 'right' }
  );
}

Put this in process.js, then reference it: { "id": "options_grid", "type": "grid", "columns": 2, "data": "inputs.gridData" }.

A more compact equivalent once the loop is familiar:

inputs.gridData = inputs.options.flatMap(function (o) {
  return [{ text: o.description }, { text: '$' + o.price, 'text-align': 'right' }];
});

Both produce the same array - style preference, not a different feature.