Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/data/data-grid/layout/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ You can predefine dimensions for the parent of the Data Grid.
## Height prop

Use the `height` prop to set a fixed height directly on the Data Grid, without a parent element with an explicit height.
It accepts a number (in pixels) or any valid CSS height value, such as `'50vh'`.
It accepts a number (in pixels), a CSS length such as `'50vh'`, a percentage, or a calculation such as `'calc(100vh - 200px)'`.
Percentage values require a parent element with an explicit height.
For content-based sizing, use a [flex parent container](#flex-parent-container) instead of values such as `'auto'`, `'min-content'`, `'max-content'`, or `'fit-content'`, which this prop does not support.
To change the height, update the prop instead of `sx` or `style`, because the prop also sets the minimum and maximum height.

{{"demo": "HeightGrid.js", "bg": "inline"}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@
"description": "If <code>true</code>, the header filters feature is enabled."
},
"height": {
"description": "The height of the Data Grid. Accepts a number (pixels) or any valid CSS height value (for example <code>&#39;50vh&#39;</code>). When set, the Data Grid no longer needs a parent element with an explicit height."
"description": "The fixed height of the Data Grid. Accepts a number (pixels), a CSS length (for example <code>&#39;50vh&#39;</code>), a percentage, or a CSS calculation. Percentage values require a parent with an explicit height. Content-based values such as <code>&#39;auto&#39;</code>, <code>&#39;min-content&#39;</code>, <code>&#39;max-content&#39;</code>, and <code>&#39;fit-content&#39;</code> are not supported. For content-based sizing, use a flex parent container instead."
},
"hideFooter": { "description": "If <code>true</code>, the footer component is hidden." },
"hideFooterPagination": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
"description": "If <code>true</code>, the header filters feature is enabled."
},
"height": {
"description": "The height of the Data Grid. Accepts a number (pixels) or any valid CSS height value (for example <code>&#39;50vh&#39;</code>). When set, the Data Grid no longer needs a parent element with an explicit height."
"description": "The fixed height of the Data Grid. Accepts a number (pixels), a CSS length (for example <code>&#39;50vh&#39;</code>), a percentage, or a CSS calculation. Percentage values require a parent with an explicit height. Content-based values such as <code>&#39;auto&#39;</code>, <code>&#39;min-content&#39;</code>, <code>&#39;max-content&#39;</code>, and <code>&#39;fit-content&#39;</code> are not supported. For content-based sizing, use a flex parent container instead."
},
"hideFooter": { "description": "If <code>true</code>, the footer component is hidden." },
"hideFooterPagination": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
}
},
"height": {
"description": "The height of the Data Grid. Accepts a number (pixels) or any valid CSS height value (for example <code>&#39;50vh&#39;</code>). When set, the Data Grid no longer needs a parent element with an explicit height."
"description": "The fixed height of the Data Grid. Accepts a number (pixels), a CSS length (for example <code>&#39;50vh&#39;</code>), a percentage, or a CSS calculation. Percentage values require a parent with an explicit height. Content-based values such as <code>&#39;auto&#39;</code>, <code>&#39;min-content&#39;</code>, <code>&#39;max-content&#39;</code>, and <code>&#39;fit-content&#39;</code> are not supported. For content-based sizing, use a flex parent container instead."
},
"hideFooter": { "description": "If <code>true</code>, the footer component is hidden." },
"hideFooterPagination": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -755,9 +755,11 @@ DataGridPremiumRaw.propTypes /* remove-proptypes */ = {
*/
headerFilters: PropTypes.bool,
/**
* The height of the Data Grid.
* Accepts a number (pixels) or any valid CSS height value (for example `'50vh'`).
* When set, the Data Grid no longer needs a parent element with an explicit height.
* The fixed height of the Data Grid.
* Accepts a number (pixels), a CSS length (for example `'50vh'`), a percentage, or a CSS calculation.
* Percentage values require a parent with an explicit height.
* Content-based values such as `'auto'`, `'min-content'`, `'max-content'`, and `'fit-content'` are not supported.
* For content-based sizing, use a flex parent container instead.
*/
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
Expand Down
8 changes: 5 additions & 3 deletions packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,11 @@ DataGridProRaw.propTypes /* remove-proptypes */ = {
*/
headerFilters: PropTypes.bool,
/**
* The height of the Data Grid.
* Accepts a number (pixels) or any valid CSS height value (for example `'50vh'`).
* When set, the Data Grid no longer needs a parent element with an explicit height.
* The fixed height of the Data Grid.
* Accepts a number (pixels), a CSS length (for example `'50vh'`), a percentage, or a CSS calculation.
* Percentage values require a parent with an explicit height.
* Content-based values such as `'auto'`, `'min-content'`, `'max-content'`, and `'fit-content'` are not supported.
* For content-based sizing, use a flex parent container instead.
*/
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
Expand Down
60 changes: 59 additions & 1 deletion packages/x-data-grid-pro/src/tests/printExport.DataGrid.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { RefObject } from '@mui/x-internals/types';
import { DataGridPro, GridPrintExportMenuItem, useGridApiRef } from '@mui/x-data-grid-pro';
import {
DataGridPro,
GridPrintExportMenuItem,
gridClasses,
useGridApiRef,
} from '@mui/x-data-grid-pro';
import type { GridApi, DataGridProProps } from '@mui/x-data-grid-pro';
import MenuList from '@mui/material/MenuList';
import { getBasicGridData } from '@mui/x-data-grid-generator';
Expand Down Expand Up @@ -193,6 +198,59 @@ describe('<DataGridPro /> - Print export', () => {
});
});

describe('print height', () => {
it.skipIf(isJSDOM).each([
{ height: 1200, rowCount: 3 },
{ height: 300, rowCount: 30 },
])('fits $rowCount exported rows when height={$height}', async ({ height, rowCount }) => {
const { setProps } = render(
<Test {...getBasicGridData(rowCount, 2)} height={height} rowHeight={40} />,
);

const printLayouts: { height: number; footerGap: number; rowCount: number }[] = [];
const removeChild = document.body.removeChild.bind(document.body);
const removeChildSpy = vi
.spyOn(document.body, 'removeChild')
.mockImplementation(<T extends Node>(child: T): T => {
if (child instanceof HTMLIFrameElement) {
const printRoot = child.contentDocument!.querySelector<HTMLElement>(
`.${gridClasses.root}`,
)!;
const rows = printRoot.querySelectorAll<HTMLElement>(`.${gridClasses.row}`);
const lastRow = rows[rows.length - 1].getBoundingClientRect();
const footer = printRoot
.querySelector<HTMLElement>(`.${gridClasses.footerContainer}`)!
.getBoundingClientRect();
printLayouts.push({
height: printRoot.getBoundingClientRect().height,
footerGap: footer.top - lastRow.bottom,
rowCount: rows.length,
});
}
return removeChild(child);
});
onTestFinished(() => removeChildSpy.mockRestore());

async function exportGrid() {
let printPromise!: Promise<void>;
// Flush the virtualization update before the async export clones the grid in React 18.
act(() => {
printPromise = apiRef.current!.exportDataAsPrint();
});
await act(() => printPromise);
}

await exportGrid();

setProps({ height: undefined });
await exportGrid();

// The height prop must not change the exported content height or footer position.
expect(printLayouts.map((layout) => layout.rowCount)).to.deep.equal([rowCount, rowCount]);
expect(printLayouts[0]).to.deep.equal(printLayouts[1]);
});
});

describe('stylesheets that fail to load', () => {
function addMissingStylesheet() {
const link = document.createElement('link');
Expand Down
8 changes: 5 additions & 3 deletions packages/x-data-grid/src/DataGrid/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,11 @@ DataGridRaw.propTypes /* remove-proptypes */ = {
*/
getRowSpacing: PropTypes.func,
/**
* The height of the Data Grid.
* Accepts a number (pixels) or any valid CSS height value (for example `'50vh'`).
* When set, the Data Grid no longer needs a parent element with an explicit height.
* The fixed height of the Data Grid.
* Accepts a number (pixels), a CSS length (for example `'50vh'`), a percentage, or a CSS calculation.
* Percentage values require a parent with an explicit height.
* Content-based values such as `'auto'`, `'min-content'`, `'max-content'`, and `'fit-content'` are not supported.
* For content-based sizing, use a flex parent container instead.
*/
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,7 @@ export const GridRootStyles = styled('div', {
'--DataGrid-bottomContainerHeight': '0px',
'--DataGrid-horizontalFiller': '0px',

// flex-grow stays on to still fill a flex-row parent's width; flex-shrink: 0
// plus maxHeight below stop a flex-column parent from resizing the root away
// from the requested height. See https://github.com/mui/mui-x/pull/23628#discussion_r4046270137
flex: ownerState.height != null ? '1 0 auto' : 1,
flex: 1,
boxSizing: 'border-box',
position: 'relative',
borderWidth: '1px',
Expand All @@ -187,10 +184,12 @@ export const GridRootStyles = styled('div', {
font: vars.typography.font.body,
outline: 'none',
height: ownerState.height ?? '100%',
// Pin the `height` prop in a flex-column parent without flex-shrink: 0, which would make
// a flex-row parent overflow. See https://github.com/mui/mui-x/pull/23628#discussion_r4046270137
minHeight: ownerState.height ?? 0,
maxHeight: ownerState.height,
display: 'flex',
minWidth: 0, // See https://github.com/mui/mui-x/issues/8547
minHeight: 0,
flexDirection: 'column',
overflow: 'hidden',
transform: 'translate(0, 0)', // Create a stacking context to keep scrollbars from showing on top
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ export const useGridPrintExport = (
}

gridClone.style.height = 'auto';
gridClone.style.minHeight = '0';
gridClone.style.maxHeight = 'none';
// The height above does not include grid border width, so we need to exclude it
gridClone.style.boxSizing = 'content-box';

Expand Down
8 changes: 5 additions & 3 deletions packages/x-data-grid/src/models/props/DataGridProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,11 @@ export interface DataGridPropsWithoutDefaultValue<
*/
scrollbarSize?: number;
/**
* The height of the Data Grid.
* Accepts a number (pixels) or any valid CSS height value (for example `'50vh'`).
* When set, the Data Grid no longer needs a parent element with an explicit height.
* The fixed height of the Data Grid.
* Accepts a number (pixels), a CSS length (for example `'50vh'`), a percentage, or a CSS calculation.
* Percentage values require a parent with an explicit height.
* Content-based values such as `'auto'`, `'min-content'`, `'max-content'`, and `'fit-content'` are not supported.
* For content-based sizing, use a flex parent container instead.
*/
height?: number | string;
/**
Expand Down
32 changes: 31 additions & 1 deletion packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,18 @@ describe('<DataGrid /> - Layout & warnings', () => {
expect(getComputedStyle(grid('root')!).height).to.equal('150px');
});

it.each(['50%', 'calc(100% - 300px)', 'var(--grid-height)'])(
'should resolve height=%s inside a flex column container',
(height) => {
render(
<div style={{ display: 'flex', flexDirection: 'column', height: 600 }}>
<DataGrid {...baselineProps} height={height} sx={{ '--grid-height': '300px' }} />
</div>,
);
expect(grid('root')).toHaveComputedStyle({ height: '300px' });
},
);

it('should let autoPageSize compute the page size from the height prop, without a wrapper', () => {
const nbRows = 27;
const height = 780;
Expand Down Expand Up @@ -906,7 +918,8 @@ describe('<DataGrid /> - Layout & warnings', () => {
});

it('should let sx override the height prop', () => {
render(<DataGrid {...baselineProps} height={300} sx={{ height: 150 }} />);
// The prop also sets `minHeight`, so the override has to set it too.
render(<DataGrid {...baselineProps} height={300} sx={{ height: 150, minHeight: 150 }} />);
expect(getComputedStyle(grid('root')!).height).to.equal('150px');
});

Expand Down Expand Up @@ -958,6 +971,23 @@ describe('<DataGrid /> - Layout & warnings', () => {
);
expect(grid('root')).toHaveComputedStyle({ width: '400px' });
});

// Need layout
it.skipIf(isJSDOM)(
'should not overflow a flex row container narrower than the columns',
() => {
render(
<div style={{ display: 'flex', width: 300 }}>
<DataGrid
{...baselineProps}
columns={[{ field: 'brand', width: 500 }]}
height={300}
/>
</div>,
);
expect(grid('root')).toHaveComputedStyle({ width: '300px' });
},
);
});

// A function test counterpart of ScrollbarOverflowVerticalSnap.
Expand Down
Loading