Skip to main content
react-md
react-md - Utils - Demos

App Size Listener Example

The AppSizeListener component is used to determine the current application size based on media queries. You normally want to add this component near the root of your app and then use the useAppSize hook to determine the current app size within child components.

If you are using the @react-md/layout package, this will be handled for you automatically.

The current app size will contain the following keys:

interface AppSize {
  isPhone: boolean;
  isTablet: boolean;
  isDesktop: boolean;
  isLargeDesktop: boolean;
  isLandscape: boolean;
}

which will be determined by different min and max widths passed into the AppSizeListener component.

The default breakpoints and media queries will be:

const isPhone = "screen and (max-width: 767px)";
const isTablet = "screen and (min-width: 768px) and (max-width: 1024px)";
const isDesktop = "screen and (min-width: 1025px)";
const isLargeDesktop = "screen and (min-width: 1280px)";
const isLandscape = window.innerWidth > window.innerHeight;

The media queries will actually be using em instead of pixels, but I converted this example to pixels for human readability.

The current app size is:
{
  "isPhone": false,
  "isTablet": false,
  "isDesktop": true,
  "isLargeDesktop": false,
  "isLandscape": true
}

Media Query Components

This package also exports some helper components that allow you to render specific parts only when the AppSize matches specific devices. Since I want to try to keep the app size minimal, the default helper components are:

  • PhoneOnly
  • TabletOnly
  • DesktopOnly
  • MobileOnly

You can always hook into the AppSizeContext and implement more specific implementations if the need arises in your app.

This package also exposes some mixins that allow you to apply styles at specific breakpoints as well:

  • rmd-utils-phone-media
  • rmd-utils-tablet-only-media
  • rmd-utils-tablet-media
  • rmd-utils-desktop-media
  • rmd-utils-large-desktop-media

The rmd-utils-phone-media and rmd-utils-tablet-only-media will be the only mixins that allow for the breakpoints to prevent styles in large screen sizes while the rmd-utils-tablet-media, rmd-utils-desktop-media and rmd-utils-large-desktop-media will work by using the min-width of the specific media matcher.

The example below will showcase the *Only components and render text when the app size matches as well as a few examples of using the mixins to add dynamic styles based on the screen size.

This will only appear on desktop screen sizes.

This section will gain different styles as the viewport increases. I highly recommend opening the dev tools and seeing how the different styles get applied and when some are completely removed to get a better understanding of the media queries.

Resize Listener Example

This package also exports a ResizeListener component that will listen to entire window resize events while mounted. The resize event callback will be throttled for extra performance as well as delegating the event using the @react-md/utils delegateEvent helper. This is extremely useful when you need to track specific pixel updates instead of breakpoint changes.

The example below will update the current app size in pixels while the listener is enabled. You can toggle the two checkboxes to see the different behavior for the immediate prop and how the ResizeListener stops triggering callbacks while unmounted.

The current app size is:

0px

Resize Observer Example

The useResizeObserver hook is useful when you want to watch a specific element resize when it can't be handled just by an entire page resize listener. The ResizeObserver is useful when you want to watch a specific element resizing when it can't be handled just by an entire page resize listener. This hook returns an ordered list containing a ref object containing the current element if you need access to that element and a refHandler that should be passed to the target element.

The example below will animating between different max heights and max widths once the "Start" button is pressed and show the current height and width values within the table.

Height:110
Width:150

Material Grid Example

The grid system in material design is a bit confusing if you are coming from another CSS grid system like the bootstrap grid system since the number of columns changes depending on the viewport size. The grid system will have:

  • 4 columns on mobile
  • 8 columns on tablet
  • 12 columns on desktop

The dynamic columns are actually pretty nice since having a cell that spans 1 column on desktop and 1 column on mobile would normally have an extremely small column on mobile. However, the second you start using cells that span more than one column, it becomes a bit harder to layout your grid. The grid has some "safeguarding" built in so that if you attempt to make a cell span more columns than available at the current viewport, it will update itself to just be full width instead.

The example below will show some examples of rendering cells and spanning a few columns by using the Grid and GridCell components.

Note: You can opt out of this behavior and have static columns by either setting the $rmd-grid-columns variable or by providing a columns prop to the Grid component. This component also relies on the AppSizeListener as a parent component for media query updates and will throw an error if it does not exist.

Cell 1
Cell 2
Cell 3
Cell 4
Cell 5
Cell 6
Cell 7
Cell 8
Cell 9
Cell 10
Cell 11
Cell 12
Cell 1
Cell 2
Cell 3
Cell 4
Cell 5
Cell 6
Cell 1
Cell 2
Cell 3
Cell 4
Cell 5
Cell 6
Cell 7
Cell 8
Cell 1
Cell 2
Cell 3
Cell 1
Cell 2
Cell 1
Cell 2
Cell 1
Cell 2
Cell 1
Cell 2
Cell 1
Cell 2
Cell 1
Cell 2
Cell 1
Cell 2
Cell 1

Simple Grid List

Most grid systems define a static number of columns that should appear on each row and have each cell have a percentage width based on how many columns they should span. One of the most well-known ones is the bootstrap grid system that defines a 12 column grid system. This is nice for a lot of cases, but it is a bit restrictive since you'll need to test every single viewport width to ensure that each cell shows up nicely and add additional breakpoints to increase cell width as needed. What if you just want to say:

"I don't care how many columns there are at a time, but each cell should grow up to Xpx and columns should be added as needed"?"

This is where the GridList component comes in handy since that's exactly what it does. This component will try to show as many columns as possible by trying to render as many "full width" cells as possible until it reaches the container's width. If there is still some leftover room, each cell will shrink and a new column will be added.

The example below will allow you to configure:

  • the number of cells
  • each cell's margin (optional prop) that gets applied to the top, right, bottom, and left of each cell
  • each cell's max-width (optional prop)
  • the container's padding (optional prop)

The containerPadding prop is a bit weird as it is really the total number of pixels to subtract from the container.offsetWidth since padding and border widths are included. The GridList will automatically subtract the current visible scrollbar width (if the OS renders them inline with content), but there isn't anything built in at this time to subtract padding and border for performance concerns. It's much easier to just update this value if you change the padding or add a border to this component.

GridList options
Cell 1
Cell 2
Cell 3
Cell 4
Cell 5
Cell 6
Cell 7
Cell 8
Cell 9
Cell 10
Cell 11
Cell 12
Cell 13
Cell 14
Cell 15
Cell 16
Cell 17
Cell 18
Cell 19
Cell 20

Grid List Size

The current number of columns and the size of each column can be retrieved either with the useGridListSize hook or using the "children render function" pattern. If you want to use the children render function pattern, a quick example is:

<GridList>
  {({ columns, cellWidth }) => (
    <GridListCell>
      Columns: {columns}
      <br />
      Cell Width: {cellWidth}
    </GridListCell>
  )}
</GridList>

However, the hook API is easier to understand so the following example will use the useGridListSize hook instead.

Note: The grid list size will be 0 if server side rendering since the GridList requires access to the DOM to calculate sizing.

Columns:-1
Cell Width:150

Hover Mode

react-md@2.8.0 introduces a new public hover mode API that allows different temporary elements like tooltips and popover dialogs to appear immediately after an element has been hovered instead of waiting the default hover duration (1s). To use this functionality you'll need to:

  • render the HoverModeProvider or Configuration (from @react-md/layout) component as a parent component
  • use the useHoverMode hook to provide the mouse event handlers, visibility, and other functionality

I recommend checking out the useHoverMode type definitions for more information around what's returned.

The example below will show how you can use the hover mode API to create a Wikipedia-like preview window while hovering over links.

Material Design (codenamed Quantum Paper) Design Language "card" motifs that debuted in Google Now , Material Design uses more grid-based layouts, responsive animations and transitions, padding, and depth effects such as lighting and shadows. Google announced Material Design on June 25, 2014, at the 2014 Google I/O conference.

Sticky Hover Mode

The useHoverMode hook can also be updated to implement a "sticky" spec that allows the user to click the element to toggle the visibility state. Once the element has been clicked, the onMouseEnter and onMouseLeave behavior will be disabled until the visibility is set to false once more.