This section shows how the detail height can be customised to suit application requirements.
Detail Height Options Copy Link
The default height of each detail section (ie the row containing the Detail Grid in the master) is fixed at 300px. The height does not change based on how much data there is to display in the detail section.
To change the height of the details section from the default you have the following options:
Fixed Height: a custom fixed height can be provided for all detail sections instead of the default
300px.Auto Height: detail sections can auto-size to fit based off the contents.
Dynamic Height: different heights can be provided for each detail section.
Fixed Height Copy Link
Use the grid property detailRowHeight to set a fixed height for each detail row.
<ag-grid-vue
:detailRowHeight="detailRowHeight"
/* other grid options ... */>
</ag-grid-vue>
// statically fix row height for all detail grids
this.detailRowHeight = 200;The following example sets a fixed row height for all detail rows.
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
FirstDataRenderedEvent,
GridApi,
GridOptions,
GridReadyEvent,
IDetailCellRendererParams,
ModuleRegistry,
RowApiModule,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RowApiModule,
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
]);
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:masterDetail="true"
:detailRowHeight="detailRowHeight"
:detailCellRendererParams="detailCellRendererParams"
:alwaysShowVerticalScroll="true"
:rowData="rowData"
@first-data-rendered="onFirstDataRendered"></ag-grid-vue>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi<IAccount> | null>(null);
const columnDefs = ref<ColDef[]>([
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
});
const detailRowHeight = ref(200);
const detailCellRendererParams = ref({
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number", minWidth: 150 },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode", minWidth: 150 },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>);
const rowData = ref<IAccount[]>(null);
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data) => {
rowData.value = data;
};
fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
.then((resp) => resp.json())
.then((data) => updateData(data));
};
return {
gridApi,
columnDefs,
defaultColDef,
detailRowHeight,
detailCellRendererParams,
rowData,
onGridReady,
onFirstDataRendered,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
Auto Height Copy Link
Set grid property detailRowAutoHeight=true to have the detail grid dynamically change its height to fit its rows.
<ag-grid-vue
:detailRowAutoHeight="detailRowAutoHeight"
/* other grid options ... */>
</ag-grid-vue>
// dynamically set row height for all detail grids
this.detailRowAutoHeight = true;import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
FirstDataRenderedEvent,
GridApi,
GridOptions,
GridReadyEvent,
IDetailCellRendererParams,
ModuleRegistry,
RowApiModule,
enableDevValidations,
} from "ag-grid-community";
import { MasterDetailModule } from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RowApiModule,
ClientSideRowModelModule,
MasterDetailModule,
]);
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:masterDetail="true"
:detailRowAutoHeight="true"
:detailCellRendererParams="detailCellRendererParams"
:alwaysShowVerticalScroll="true"
:rowData="rowData"
@first-data-rendered="onFirstDataRendered"></ag-grid-vue>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi<IAccount> | null>(null);
const columnDefs = ref<ColDef[]>([
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
});
const detailCellRendererParams = ref({
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number", minWidth: 150 },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode", minWidth: 150 },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>);
const rowData = ref<IAccount[]>(null);
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data) => {
rowData.value = data;
};
fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
.then((resp) => resp.json())
.then((data) => updateData(data));
};
return {
gridApi,
columnDefs,
defaultColDef,
detailCellRendererParams,
rowData,
onGridReady,
onFirstDataRendered,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
When using Auto Height, the Detail Grid will have a minimum height of 150px for the rows section, and no maximum height. See Minimum and Maximum Height with Auto Height for more information on how to change this.
If you do not set a maximum height when enabling Auto Height, the Detail Grid will render all of its rows all the time. Row Virtualisation will not happen. This means if the Detail Grid has many rows, it could slow down your application and could result in stalling the browser.
If you have large data sets in detail rows, say 100+ rows, ensure that you set a value for the autoHeightMaxBodyHeight theme parameter.
Auto Height with Custom Detail Copy Link
If you are providing your own Detail Cell Renderer, set detailRowAutoHeight: true in the master-level gridOptions and ensure the content nested inside the detail cell renderer component sets a height value.
Here is an example of Auto Height being used with a Custom Detail Cell Renderer:
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
FirstDataRenderedEvent,
GridApi,
GridOptions,
GridReadyEvent,
IDetailCellRendererParams,
ModuleRegistry,
RowApiModule,
enableDevValidations,
} from "ag-grid-community";
import { MasterDetailModule } from "ag-grid-enterprise";
import { IAccount, ICallRecord } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RowApiModule,
ClientSideRowModelModule,
MasterDetailModule,
]);
export class DetailCellRenderer {
eGui: HTMLDivElement | undefined;
init() {
this.eGui = document.createElement("div");
//additional content shown in detail
const panel = document.createElement("div");
// Notice: the height is set
panel.style =
"height:100px; background-color:lightblue; padding: 15px; font-weight: bold; ";
panel.innerText = "Optional element content";
// button to toggle optional content visibility
const btn = document.createElement("button");
btn.innerText = "Show Optional Element";
btn.style = "margin:10px";
btn.addEventListener("click", function (p: any) {
//add your own condition here based on application logic - this only checks the number of children shown
if (p.target.parentElement.children.length === 1) {
p.target.parentElement.appendChild(panel);
p.target.innerText = "Hide Optional Element";
} else {
p.target.parentElement.removeChild(panel);
p.target.innerText = "Show Optional Element";
}
});
this.eGui.appendChild(btn);
}
getGui() {
return this.eGui;
}
refresh() {
return false;
}
}
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:masterDetail="true"
:detailRowAutoHeight="true"
:detailCellRendererParams="detailCellRendererParams"
:detailCellRenderer="detailCellRenderer"
:rowData="rowData"
@first-data-rendered="onFirstDataRendered"></ag-grid-vue>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi<IAccount> | null>(null);
const columnDefs = ref<ColDef[]>([
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
});
const detailCellRendererParams = ref({
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number", minWidth: 150 },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode", minWidth: 150 },
],
defaultColDef: {
flex: 1,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>);
const detailCellRenderer = ref(DetailCellRenderer);
const rowData = ref<IAccount[]>(null);
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data) => {
rowData.value = data;
};
fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
.then((resp) => resp.json())
.then((data) => updateData(data));
};
return {
gridApi,
columnDefs,
defaultColDef,
detailCellRendererParams,
detailCellRenderer,
rowData,
onGridReady,
onFirstDataRendered,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
Dynamic Height Copy Link
Use the callback getRowHeight(params) to set height for each row individually. This is a specific use of the callback that is explained in more detail in Get Row Height
Callback version of property rowHeight to set height for each row individually. Function should return a positive number of pixels, or return null/undefined to use the default row height. |
Note that this callback gets called for all rows in the Master Grid, not just rows containing Detail Grids. If you do not want to set row heights explicitly for other rows simply return undefined / null and the grid will ignore the result for that particular row.
<ag-grid-vue
:getRowHeight="getRowHeight"
/* other grid options ... */>
</ag-grid-vue>
// dynamically assigning detail row height
this.getRowHeight = params => {
const isDetailRow = params.node.detail;
// for all rows that are not detail rows, return nothing
if (!isDetailRow) { return undefined; }
// otherwise return height based on number of rows in detail grid
const detailPanelHeight = params.data.children.length * 50;
return detailPanelHeight;
};The following example demonstrates dynamic detail row heights:
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
ClientSideRowModelModule,
ColDef,
ColGroupDef,
FirstDataRenderedEvent,
GetRowHeight,
GridApi,
GridOptions,
GridReadyEvent,
IDetailCellRendererParams,
ModuleRegistry,
RenderApiModule,
RowApiModule,
RowHeightParams,
enableDevValidations,
} from "ag-grid-community";
import {
ColumnMenuModule,
ColumnsToolPanelModule,
ContextMenuModule,
MasterDetailModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
RenderApiModule,
RowApiModule,
ClientSideRowModelModule,
ColumnsToolPanelModule,
MasterDetailModule,
ColumnMenuModule,
ContextMenuModule,
]);
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:masterDetail="true"
:detailCellRendererParams="detailCellRendererParams"
:getRowHeight="getRowHeight"
:alwaysShowVerticalScroll="true"
:rowData="rowData"
@first-data-rendered="onFirstDataRendered"></ag-grid-vue>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi | null>(null);
const columnDefs = ref<ColDef[]>([
// group cell renderer needed for expand / collapse icons
{ field: "name", cellRenderer: "agGroupCellRenderer" },
{ field: "account" },
{ field: "calls" },
{ field: "minutes", valueFormatter: "x.toLocaleString() + 'm'" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
});
const detailCellRendererParams = ref<any>({
detailGridOptions: {
columnDefs: [
{ field: "callId" },
{ field: "direction" },
{ field: "number" },
{ field: "duration", valueFormatter: "x.toLocaleString() + 's'" },
{ field: "switchCode" },
],
defaultColDef: {
flex: 1,
},
onGridReady: (params) => {
// using auto height to fit the height of the the detail grid
params.api.setGridOption("domLayout", "autoHeight");
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.callRecords);
},
} as IDetailCellRendererParams<IAccount, ICallRecord>);
const getRowHeight = ref<GetRowHeight>((params: RowHeightParams) => {
if (params.node && params.node.detail) {
const offset = 80;
const allDetailRowHeight =
params.data.callRecords.length *
params.api.getSizesForCurrentTheme().rowHeight;
const gridSizes = params.api.getSizesForCurrentTheme();
return (
allDetailRowHeight +
((gridSizes && gridSizes.headerHeight) || 0) +
offset
);
}
});
const rowData = ref<any[]>(null);
function onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(() => {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data) => {
rowData.value = data;
};
fetch(
"https://www.ag-grid.com/example-assets/master-detail-dynamic-row-height-data.json",
)
.then((resp) => resp.json())
.then((data) => updateData(data));
};
return {
gridApi,
columnDefs,
defaultColDef,
detailCellRendererParams,
getRowHeight,
rowData,
onGridReady,
onFirstDataRendered,
};
},
});
const app = createApp(VueExample);
app.mount("#app");