UIコンポーネントのレスポンシブ対応

UIコンポーネントのレスポンシブ対応は、画面サイズに応じてコンポーネントの表示・レイアウト・挙動を切り替える設定。ナビゲーションをハンバーガーメニューに切り替える、テーブルをカード表示に変える、モーダルをドロワーにするなどの対応が含まれる。

Mantine・MUI・Ant Design はブレークポイントを検知するフック(useMediaQuery / useBreakpoint)を内蔵しており、JavaScriptレベルでのコンポーネント切り替えが容易。shadcn/ui は Tailwind CSS のブレークポイントユーティリティとの組み合わせが基本で、useMediaQuery のサンプルコードも提供している。

主なバリエーション
  • ブレークポイント対応 props(レスポンシブオブジェクト構文)
  • レスポンシブグリッド(列数の切り替え)
  • 画面サイズ別の表示/非表示
  • モバイル時のコンポーネント切り替え(例: Dialog → Drawer)
  • レスポンシブフォントサイズ・スペーシング
  • useMediaQuery 等のフック提供

ライブラリ横断比較

機能MantineAnt Designshadcn/uiMUI
ブレークポイント対応 props
オブジェクト構文
xs/sm/md/lg/xl
Tailwindクラス
sx breakpoints
レスポンシブグリッド
Grid.Col span={}
Row/Col
Tailwind grid
Grid size={}
画面サイズ別の表示/非表示
hiddenFrom/visibleFrom
Col xs=0 等
Tailwind hidden/block
sx display:{}
コンポーネント切り替え
useMediaQuery
useBreakpoint
useMediaQuery
useMediaQuery
レスポンシブフォントサイズ
fz prop
style
Tailwind text-*
sx / Typography
useMediaQuery 等のフック提供
@mantine/hooks
Grid.useBreakpoint
サンプル提供のみ
@mui/material

○ = 対応  △ = 部分対応・制限あり  × = 非対応

ライブラリ別コード例

各ライブラリでレスポンシブ対応を実装する際の設定部分を抜粋しています。 動くデモは各比較ページでご確認ください。

Mantine

// Mantine のレスポンシブ対応
import { Grid, Box, Button } from '@mantine/core';
import { useMediaQuery } from '@mantine/hooks';

// Grid でレスポンシブ列数(base/xs/sm/md/lg/xl のオブジェクト構文)
<Grid>
  <Grid.Col span={{ base: 12, sm: 6, md: 4 }}>コンテンツ1</Grid.Col>
  <Grid.Col span={{ base: 12, sm: 6, md: 4 }}>コンテンツ2</Grid.Col>
  <Grid.Col span={{ base: 12, sm: 12, md: 4 }}>コンテンツ3</Grid.Col>
</Grid>

// 画面サイズ別の表示/非表示(hiddenFrom / visibleFrom)
<Box hiddenFrom="sm">モバイルのみ表示されるメニュー</Box>
<Box visibleFrom="sm">タブレット以上で表示されるメニュー</Box>

// useMediaQuery フック(@mantine/hooks)
function ResponsiveNav() {
  const isMobile = useMediaQuery('(max-width: 768px)');
  return isMobile ? <HamburgerMenu /> : <HorizontalNav />;
}

// Button の fullWidth・レスポンシブサイズ
<Button fullWidth>モバイルでフル幅ボタン</Button>
<Button size={{ base: 'sm', md: 'lg' }}>レスポンシブサイズ</Button>

// フォントサイズのレスポンシブ対応(fz prop)
import { Text } from '@mantine/core';
<Text fz={{ base: 'sm', md: 'lg' }} fw={700}>レスポンシブテキスト</Text>

Ant Design

// Ant Design のレスポンシブ対応
import { Row, Col, Grid, Drawer } from 'antd';
import { useState } from 'react';
const { useBreakpoint } = Grid;

// Row/Col でレスポンシブグリッド(xs/sm/md/lg/xl/xxl)
<Row gutter={[16, 16]}>
  <Col xs={24} sm={12} md={8}>コンテンツ1</Col>
  <Col xs={24} sm={12} md={8}>コンテンツ2</Col>
  <Col xs={24} sm={24} md={8}>コンテンツ3</Col>
</Row>

// useBreakpoint で各ブレークポイントの状態をオブジェクトで取得
function ResponsiveNav() {
  const [open, setOpen] = useState(false);
  const screens = useBreakpoint();
  // screens = { xs: true, sm: false, md: false, lg: false, xl: false }

  if (!screens.md) {
    return (
      <>
        <button onClick={() => setOpen(true)}>メニュー</button>
        <Drawer open={open} onClose={() => setOpen(false)} placement="left">
          <MenuContent />
        </Drawer>
      </>
    );
  }
  return <Sider><MenuContent /></Sider>;
}

// Col の表示/非表示(xs=0 で非表示)
<Col xs={{ span: 0 }} sm={{ span: 24 }}>
  タブレット以上のみ表示
</Col>

shadcn/ui

// shadcn/ui は Tailwind CSS のブレークポイントで対応
// useMediaQuery フックは shadcn/ui のドキュメントで実装例が提供されている
import { useMediaQuery } from '@/hooks/use-media-query';
import { Dialog, DialogContent } from '@/components/ui/dialog';
import { Drawer, DrawerContent } from '@/components/ui/drawer';

// Tailwind でレスポンシブグリッド(モバイルファースト)
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
  <div>コンテンツ1</div>
  <div>コンテンツ2</div>
  <div>コンテンツ3</div>
</div>

// 表示/非表示(Tailwind の hidden/block)
<div className="block md:hidden">モバイルのみ表示</div>
<div className="hidden md:block">タブレット以上で表示</div>

// useMediaQuery でダイアログ/ドロワーを切り替え
function ResponsiveModal({ open, setOpen }: { open: boolean; setOpen: (v: boolean) => void }) {
  const isDesktop = useMediaQuery('(min-width: 768px)');

  if (isDesktop) {
    return (
      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent>デスクトップ用ダイアログ</DialogContent>
      </Dialog>
    );
  }
  return (
    <Drawer open={open} onOpenChange={setOpen}>
      <DrawerContent>モバイル用ドロワー</DrawerContent>
    </Drawer>
  );
}

// レスポンシブフォントサイズ(Tailwind)
<h1 className="text-2xl md:text-4xl lg:text-5xl font-bold">
  レスポンシブ見出し
</h1>

MUI

// MUI のレスポンシブ対応(Grid2 + sx + useMediaQuery)
import { Grid, Box, useMediaQuery, useTheme } from '@mui/material';
import { Drawer } from '@mui/material';

// Grid2 でレスポンシブ列数(12列グリッド)
<Grid container spacing={2}>
  <Grid size={{ xs: 12, sm: 6, md: 4 }}>コンテンツ1</Grid>
  <Grid size={{ xs: 12, sm: 6, md: 4 }}>コンテンツ2</Grid>
  <Grid size={{ xs: 12, sm: 12, md: 4 }}>コンテンツ3</Grid>
</Grid>

// sx prop でレスポンシブスタイル(オブジェクト構文)
<Box
  sx={{
    display: { xs: 'none', md: 'block' },        // モバイルで非表示
    fontSize: { xs: '0.875rem', md: '1rem' },      // レスポンシブフォント
    px: { xs: 2, sm: 3, md: 4 },                  // レスポンシブpadding
  }}
>
  タブレット以上で表示
</Box>

// useMediaQuery でブレークポイント検知
function ResponsiveNav() {
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));

  return isMobile ? (
    <Drawer open={open} onClose={handleClose}>
      <NavContent />
    </Drawer>
  ) : (
    <Sidebar>
      <NavContent />
    </Sidebar>
  );
}

// Typography のレスポンシブバリアント
import { Typography } from '@mui/material';
<Typography variant="h4" sx={{ fontSize: { xs: '1.5rem', md: '2.125rem' } }}>
  レスポンシブ見出し
</Typography>

まとめ・選び方のヒント

  • props だけでレスポンシブに対応したい → Mantine({ base: 12, sm: 6, md: 4 } のオブジェクト構文で多くの props がレスポンシブ対応)・MUI(sx prop のオブジェクト構文)
  • 表示/非表示を簡潔に書きたい → Mantine(hiddenFrom="sm"visibleFrom="sm" prop が直感的)・MUI(sx={{ display: { xs: 'none', md: 'block' } }}
  • 全ブレークポイントの状態を一度に取得したい → Ant Design(useBreakpoint() がオブジェクトで全BPの状態を返す)
  • モバイルでダイアログをドロワーに切り替えたい → shadcn/ui(Dialog ↔ Drawer の切り替えパターンがドキュメントで紹介されている)