I made an appliaction in React and used the library Grommet to design my components. I defined a theme file to set breakpoints for different mobile devices:
const customBreakpoints = deepMerge(grommet, {
global: {
breakpoints: {
small: {
value: 768,
borderSize: {
xsmall: "1px",
small: "2px",
medium: "4px",
large: "6px",
xlarge: "12px"
},
edgeSize: {
none: "0px",
hair: "1px",
xxsmall: "2px",
xsmall: "3px",
small: "6px",
medium: "12px",
large: "24px",
xlarge: "48px"
},
size: {
xxsmall: "24px",
xsmall: "48px",
small: "96px",
medium: "192px",
large: "384px",
xlarge: "768px",
full: "100%"
}
},
medium: { value: 1536 },
large: {}
}
}
});
To layout the buttons I used grommets Box component:
const App = () => (
<Grommet theme={customBreakpoints}>
<ResponsiveContext.Consumer>
{size => (
<div>
<Box
direction="column"
align="center"
gap="medium"
pad="small"
overflow={{
horizontal: "auto"
}}
>
<Button
primary
hoverIndicator="true"
style={{
width: "100%"
}}
label="Next"
/>
<Box width="medium" direction="row-responsive">
<Button
primary
icon={<DocumentPdf color="white" />}
style={{
boxSizing: "border-box",
background: "red",
height: "38px",
lineHeight: "24px",
fontSize: "18px",
fontWeight: 600,
paddingLeft: "20px",
paddingRight: "20px"
}}
label="Export PDF"
/>
<Button
primary
icon={<DocumentPdf color="white" />}
style={{
boxSizing: "border-box",
background: "red",
height: "38px",
lineHeight: "24px",
fontSize: "18px",
fontWeight: 600,
paddingLeft: "20px",
paddingRight: "20px"
}}
label="Export all"
/>
</Box>
</Box>
</div>
)}
</ResponsiveContext.Consumer>
</Grommet>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
When I run the application and inspect my current window on different devices I get the following output:
and
Even with ResponsiveContext.Consumer and setting the width=size} it didn´t work.
Any suggestions?
I made a Sandbox example.
Buttons are not the driver of the layout, and their layout is controlled by the wrapper layout component, in your case, it is the Box component below the Grommet component on the codesanbox.
The Box component is automatically responsive to the custom breakpoints you have defined and that seems to work as expected, that being said, grommet does provide well-calculated out of the box breakpoint definitions that your app will use as default anyway, so unless you have special requirements for custom breakpoints, using the default usually does the trick and removes complexity.
Your code was importing ResponsiveContext, but ResponsiveContext wasn't wrapping the layout component, and it didn't use the size prop, so once those are added I think it works as expected. I only replaced the div
with ResponsiveContext (div isn't needed when using a Box), and added size
and width
prop to Box as follows:
<ResponsiveContext.Consumer>
{size => (
<Box
direction="column"
align="center"
gap="medium"
pad="small"
overflow={{
horizontal: "auto"
}}
width={size==="small" ? "200px" : "400px"}
>
...
Using the above code portion in your sandbox will give you a better idea of how to control the buttons in a responsive manner. You can play with the values on the width
prop as you see fit, currently, it sets the width of the Button to 200px on 'small' screen size, and uses 400px otherwise (I've picked random values), and you can play with the logic and values as you see fit. As you suggested, you can also use width={size}
and that will default the size of the width to the breakpoint value ('small', 'medium', 'large'...)
Here is the full code example:
import React from "react";
import ReactDOM from "react-dom";
import { Box, Button, Grommet, ResponsiveContext } from "grommet";
import { DocumentPdf } from "grommet-icons";
import { deepMerge } from "grommet/utils";
import { grommet } from "grommet/themes";
import "./styles.css";
const customBreakpoints = deepMerge(grommet, {
global: {
breakpoints: {
small: {
value: 368,
borderSize: {
xsmall: "1px",
small: "2px",
medium: "4px",
large: "6px",
xlarge: "12px"
},
edgeSize: {
none: "0px",
hair: "1px",
xxsmall: "2px",
xsmall: "3px",
small: "6px",
medium: "12px",
large: "24px",
xlarge: "48px"
},
size: {
xxsmall: "24px",
xsmall: "48px",
small: "96px",
medium: "192px",
large: "384px",
xlarge: "768px",
full: "100%"
}
},
medium: {
value: 768,
borderSize: {
xsmall: "2px",
small: "4px",
medium: "8px",
large: "12px",
xlarge: "16px"
},
edgeSize: {
none: "0px",
hair: "1px",
xxsmall: "2px",
xsmall: "3px",
small: "6px",
medium: "12px",
large: "24px",
xlarge: "48px"
},
size: {
xxsmall: "48px",
xsmall: "96px",
small: "192px",
medium: "384px",
large: "768px",
xlarge: "1200px",
full: "100%"
}
},
large: {}
}
}
});
const App = () => (
<Grommet theme={customBreakpoints}>
<ResponsiveContext.Consumer>
{size => (
<Box
direction="column"
align="center"
gap="medium"
pad="small"
overflow={{
horizontal: "auto"
}}
width={size==="small" ? "200px" : "400px"}
>
<Button
primary
hoverIndicator="true"
style={{
width: "100%"
}}
label="Next"
/>
<Button
primary
icon={<DocumentPdf color="white" />}
style={{
width: "100%"
}}
label="Export PDF"
/>
<Button
primary
icon={<DocumentPdf color="white" />}
style={{
width: "100%"
}}
label="Export all"
/>
</Box>
)}
</ResponsiveContext.Consumer>
</Grommet>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Hope this helps.