Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material UI responsive based on element size

I'm using React and MaterialUI to build a system that will display widgets inside another (not React-based) web site. I'd like to make the widgets responsive, but they need to respond to their own container width rather than the window width, as I won't know how much of the page the widget will take up.

Options I've considered:

  • Polling the container size on an interval basis
  • Polling the container size on window resize events
  • Setting up the theme breakpoints based on the container and window sizes at startup

These all seem rather ugly solutions to me. Is there an elegant way to do what I want?

like image 504
Marten Jacobs Avatar asked Mar 08 '19 08:03

Marten Jacobs


People also ask

How do you make material UI components responsive?

Responsive layouts in Material Design adapt to any possible screen size. We provide the following helpers to make the UI responsive: Grid: The Material Design responsive layout grid adapts to screen size and orientation, ensuring consistency across layouts. Container: The container centers your content horizontally.

How do I choose a responsive breakpoint?

Always keep the common breakpoints for responsive design in mind. The former usually matches common screen sizes (480px, 768px, 1024px, and 1280px). Before choosing major breakpoints, use website analytics to discern the most commonly used devices from which your site is accessed.

What is maxWidth SM?

maxWidth value defines the width of the screen that we are targeting. xl: 1920px(extra large) lg: 1280px(large) md: 960px(medium) sm: 600px(small)


1 Answers

Instead of breakpoints you can listen to changes to the component size. You can use react-use hook useMeasure to achieve that (it relies on ResizeObserver, which is supported by all major browsers), like in the following example:

/** @jsx jsx */
import { css, jsx } from '@emotion/core';
import { faAddressBook, faCoffee } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useMeasure } from 'react-use';

const useMyComponentStyle = (params) => {
    const { color } = params;
    const [ref, { width }] = useMeasure();

    const borderColor = width < 150 ? 'red' : width < 400 ? 'yellow' : 'green';
    const icon = width < 250 ? faCoffee : faAddressBook;

    const style = css`
        color: ${color};
        padding: 10px;
        border: 1px solid ${borderColor};
    `;

    return {
        ref,
        style,
        icon,
        width,
    };
};

export const MyComponent = (props) => {
    const { ref, style, icon, width } = useMyComponentStyle(props);

    return (
        <div ref={ref} css={style}>
            <FontAwesomeIcon icon={icon} />
            {props.children} [[{parseInt('' + width)}px]]
        </div>
    );
};

const containerStyle = css`
    padding: 100px 200px;
    border: 1px solid blue;
`;

export const MyContainer = () => (
    <div css={containerStyle}>
        <MyComponent color='blue'></MyComponent>
    </div>
);

ReactDOM.render(<MyContainer />, document.getElementById('root'));

The example above uses emotion for the css styles, but the style could be defined using another library, like jss or styled components, or even plain react inline style.

The component MyComponent is included inside the container component MyContainer that has left and right padding with value 200px, and you can see as you resize your browser view that the border color of MyComponent is based on the size of the component itself (red if the width of the component is less than 150px, yellow if it's less than 400px, otherwise it's green), not based on the size of the window.

like image 180
Lucas Basquerotto Avatar answered Sep 25 '22 23:09

Lucas Basquerotto