diff --git a/docs/src/docs/core/Grid.mdx b/docs/src/docs/core/Grid.mdx
index 37144371184..dabe1009097 100644
--- a/docs/src/docs/core/Grid.mdx
+++ b/docs/src/docs/core/Grid.mdx
@@ -31,7 +31,7 @@ Use xs, sm, md, lg, xl values to set spacing from `theme.spacing` or number to s
## Grow
-Set `grow` prop on Grid component to force last row take 100% of container width:
+Set `grow` prop on Grid component to force all rows to take 100% of container width:
@@ -70,6 +70,20 @@ In this example up to `md` there will be 1 column, from `md` to `lg` there will
+## Auto sized columns
+
+All columns in a row with `span` or a breakpoint of `auto` will have equal size, growing as much as they can to fill the row.
+
+In this example, the second column takes up 50% of the row while the other two columns automatically resize to fill the remaining space:
+
+
+
+## Fit column content
+
+If you set `span` or a breakpoint to `content`, the column's size will automatically adjust to match the width of its content:
+
+
+
## Change columns count
By default, grid uses 12 columns layout, you can change it by setting `columns` prop on Grid component.
diff --git a/src/mantine-core/src/Grid/Col/Col.styles.ts b/src/mantine-core/src/Grid/Col/Col.styles.ts
index 903b287bc49..c36a794c1f7 100644
--- a/src/mantine-core/src/Grid/Col/Col.styles.ts
+++ b/src/mantine-core/src/Grid/Col/Col.styles.ts
@@ -6,6 +6,8 @@ import {
MantineTheme,
} from '@mantine/styles';
+export type ColSpan = number | 'auto' | 'content';
+
interface ColStyles {
gutter: MantineNumberSize;
columns: number;
@@ -16,12 +18,12 @@ interface ColStyles {
offsetMd: number;
offsetLg: number;
offsetXl: number;
- span: number;
- xs: number;
- sm: number;
- md: number;
- lg: number;
- xl: number;
+ span: ColSpan;
+ xs: ColSpan;
+ sm: ColSpan;
+ md: ColSpan;
+ lg: ColSpan;
+ xl: ColSpan;
order: React.CSSProperties['order'];
orderXs: React.CSSProperties['order'];
orderSm: React.CSSProperties['order'];
@@ -30,8 +32,29 @@ interface ColStyles {
orderXl: React.CSSProperties['order'];
}
-const getColumnWidth = (colSpan: number, columns: number) =>
- colSpan ? `${100 / (columns / colSpan)}%` : undefined;
+const getColumnFlexBasis = (colSpan: ColSpan, columns: number) => {
+ if (colSpan === 'content') {
+ return 'auto';
+ }
+ if (colSpan === 'auto') {
+ return '0px';
+ }
+ return colSpan ? `${100 / (columns / colSpan)}%` : undefined;
+};
+
+const getColumnMaxWidth = (colSpan: ColSpan, columns: number, grow: boolean) => {
+ if (grow || colSpan === 'auto' || colSpan === 'content') {
+ return 'unset';
+ }
+ return getColumnFlexBasis(colSpan, columns);
+};
+
+const getColumnFlexGrow = (colSpan: ColSpan, grow: boolean) => {
+ if (!colSpan) {
+ return undefined;
+ }
+ return colSpan === 'auto' || grow ? 1 : 0;
+};
const getColumnOffset = (offset: number, columns: number) =>
offset ? `${100 / (columns / offset)}%` : undefined;
@@ -44,7 +67,7 @@ function getBreakpointsStyles({
columns,
grow,
}: {
- sizes: Record;
+ sizes: Record;
offsets: Record;
orders: Record;
grow: boolean;
@@ -54,10 +77,12 @@ function getBreakpointsStyles({
return MANTINE_SIZES.reduce((acc, size) => {
acc[`@media (min-width: ${theme.breakpoints[size] + 1}px)`] = {
order: orders[size],
- flexBasis: getColumnWidth(sizes[size], columns),
+ flexBasis: getColumnFlexBasis(sizes[size], columns),
flexShrink: 0,
- maxWidth: grow ? 'unset' : getColumnWidth(sizes[size], columns),
+ width: sizes[size] === 'content' ? 'auto' : undefined,
+ maxWidth: getColumnMaxWidth(sizes[size], columns, grow),
marginLeft: getColumnOffset(offsets[size], columns),
+ flexGrow: getColumnFlexGrow(sizes[size], grow),
};
return acc;
}, {});
@@ -92,13 +117,14 @@ export default createStyles(
) => ({
root: {
boxSizing: 'border-box',
- flexGrow: grow ? 1 : 0,
+ flexGrow: getColumnFlexGrow(span, grow),
order,
padding: theme.fn.size({ size: gutter, sizes: theme.spacing }) / 2,
marginLeft: getColumnOffset(offset, columns),
- flexBasis: getColumnWidth(span, columns),
+ flexBasis: getColumnFlexBasis(span, columns),
flexShrink: 0,
- maxWidth: grow ? 'unset' : getColumnWidth(span, columns),
+ width: span === 'content' ? 'auto' : undefined,
+ maxWidth: getColumnMaxWidth(span, columns, grow),
...getBreakpointsStyles({
sizes: { xs, sm, md, lg, xl },
offsets: { xs: offsetXs, sm: offsetSm, md: offsetMd, lg: offsetLg, xl: offsetXl },
diff --git a/src/mantine-core/src/Grid/Col/Col.tsx b/src/mantine-core/src/Grid/Col/Col.tsx
index 37e490df53d..6b9d82ada72 100644
--- a/src/mantine-core/src/Grid/Col/Col.tsx
+++ b/src/mantine-core/src/Grid/Col/Col.tsx
@@ -2,11 +2,11 @@ import React, { forwardRef } from 'react';
import { DefaultProps, useComponentDefaultProps } from '@mantine/styles';
import { Box } from '../../Box';
import { useGridContext } from '../Grid.context';
-import useStyles from './Col.styles';
+import useStyles, { ColSpan } from './Col.styles';
export interface ColProps extends DefaultProps, React.ComponentPropsWithoutRef<'div'> {
/** Default col span */
- span?: number;
+ span?: ColSpan;
/** Column left offset */
offset?: number;
@@ -45,19 +45,19 @@ export interface ColProps extends DefaultProps, React.ComponentPropsWithoutRef<'
offsetXl?: number;
/** Col span at (min-width: theme.breakpoints.xs) */
- xs?: number;
+ xs?: ColSpan;
/** Col span at (min-width: theme.breakpoints.sm) */
- sm?: number;
+ sm?: ColSpan;
/** Col span at (min-width: theme.breakpoints.md) */
- md?: number;
+ md?: ColSpan;
/** Col span at (min-width: theme.breakpoints.lg) */
- lg?: number;
+ lg?: ColSpan;
/** Col span at (min-width: theme.breakpoints.xl) */
- xl?: number;
+ xl?: ColSpan;
}
const defaultProps: Partial = {
@@ -69,7 +69,10 @@ const defaultProps: Partial = {
offsetXl: 0,
};
-function isValidSpan(span: number) {
+function isValidSpan(span: ColSpan) {
+ if (span === 'auto' || span === 'content') {
+ return true;
+ }
return typeof span === 'number' && span > 0 && span % 1 === 0;
}
diff --git a/src/mantine-demos/src/demos/core/Grid/Grid.demo.auto.tsx b/src/mantine-demos/src/demos/core/Grid/Grid.demo.auto.tsx
new file mode 100644
index 00000000000..1c1241472d0
--- /dev/null
+++ b/src/mantine-demos/src/demos/core/Grid/Grid.demo.auto.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Grid } from '@mantine/core';
+import { ColWrapper as Col } from './_col-wrapper';
+
+const code = `
+import { Grid } from '@mantine/core';
+
+function Demo() {
+ return (
+
+ span=auto
+ span=6
+ span=auto
+
+ );
+}
+`;
+
+function Demo() {
+ return (
+
+ 1
+ 2
+ 3
+
+ );
+}
+
+export const auto: MantineDemo = {
+ type: 'demo',
+ code,
+ component: Demo,
+};
diff --git a/src/mantine-demos/src/demos/core/Grid/Grid.demo.content.tsx b/src/mantine-demos/src/demos/core/Grid/Grid.demo.content.tsx
new file mode 100644
index 00000000000..3c376083c74
--- /dev/null
+++ b/src/mantine-demos/src/demos/core/Grid/Grid.demo.content.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Grid } from '@mantine/core';
+import { ColWrapper as Col } from './_col-wrapper';
+
+const code = `
+import { Grid } from '@mantine/core';
+
+function Demo() {
+ return (
+
+ fit content
+ 2
+
+ );
+}
+`;
+
+function Demo() {
+ return (
+
+ fit content
+ 2
+
+ );
+}
+
+export const content: MantineDemo = {
+ type: 'demo',
+ code,
+ component: Demo,
+};
diff --git a/src/mantine-demos/src/demos/core/Grid/index.ts b/src/mantine-demos/src/demos/core/Grid/index.ts
index df68478af02..171338570e5 100644
--- a/src/mantine-demos/src/demos/core/Grid/index.ts
+++ b/src/mantine-demos/src/demos/core/Grid/index.ts
@@ -6,3 +6,5 @@ export { rows } from './Grid.demo.rows';
export { flexConfigurator } from './Grid.demo.flexConfigurator';
export { responsive } from './Grid.demo.responsive';
export { columns } from './Grid.demo.columns';
+export { auto } from './Grid.demo.auto';
+export { content } from './Grid.demo.content';