レイアウトの概要
余白、比率、並び、スクロール、リサイズ、作業面など、コンテンツを配置する土台を作るコンポーネント群です。情報そのものより、配置と可変領域の責務を扱います。
カテゴリ概要コンポーネント一覧
各コンポーネントの詳細ページへ移動して、プレビュー、コード、プロパティを確認できます。
アスペクト比
AspectRatio画像、動画、iframe などのメディア枠を、指定した縦横比で保つレイアウトプリミティブです。
アセットインスペクター
AssetInspectorPanelアセットのプレビュー、タグ、メタデータ、操作をまとめて確認・編集するインスペクターパネルです。
クラスター
Clusterタグ、ボタン、短い操作群を、折り返し可能な横並びとしてまとめるレイアウトプリミティブです。
開閉パネルトグル
CollapsiblePanelToggle境界線上に配置して、左右上下の折りたたみパネルを開閉するトグルボタンです。
コンテナ
Containerページやセクションの横幅、左右余白、中央寄せを一貫して制御するレイアウトプリミティブです。
デバイスフレーム
DeviceFrameデスクトップ、タブレット、モバイルの表示サイズを切り替えられる擬似ブラウザフレームです。
グリッド
Grid列数、間隔、最小幅を指定して、カードやメディアを整列する CSS grid ラッパーです。
水平スタック
HStack操作、ラベル、短い項目を横方向に並べ、余白・揃え・折り返しを制御します。
インスペクター
InspectorPanel選択中の対象に紐づくプロパティを、セクションとフィールドで閲覧・編集するパネルです。
マーキーフレーム
MarqueeFrameパターンや画面を、擬似ブラウザと表示サイズ切り替えの中で確認するフレームです。
リサイズ可能
Resizableキーボード操作にも対応した、リサイズ可能な分割パネルレイアウトです。
スクロール領域
ScrollArea表示領域を意図的に制限し、縦横スクロールを一貫したスタイルで扱います。
空間キャンバス
SpatialCanvasパネルやノードを配置できる、ドット背景とグリッド間隔を持つキャンバス面です。
垂直スタック
VStackフォーム、カード、説明ブロックなどを縦方向に積み、余白・揃え・高さ内の配置を制御します。
補足情報
一覧でコンポーネントを選んだあとに確認する、カテゴリ全体の責務、共通ルール、使い分けです。
このカテゴリの責務
情報を直接表現するのではなく、余白、比率、並び、スクロール、可変領域の土台を安定させます。
このページの使い方
まずカテゴリの責務を確認し、迷いやすい使い分けから該当コンポーネントへ移動します。
パターンで確認する場面
デバイス幅、作業面、パネル、サイドバー、フォームなどを組み合わせた時に、固定値に頼らず破綻しないか確認します。
レイアウト系の共通ルール
カテゴリ内で共通して守るべき判断基準です。
固定高さや固定幅で見た目だけを合わせず、実際の用途に合う可変領域を設計します。
フォームやパネルの中身は、GunjoUI の Input や関連コンポーネントを compose して使います。
迷いやすい使い分け
似ているコンポーネントを選ぶ時の入口です。
単純な横並びは HStack/Cluster、縦方向のまとまりは VStack、面全体の幅制御は Container を使います。
作業面は SpatialCanvas、デバイス確認は DeviceFrame、サイズ変更が必要な領域は Resizable を使います。
最初に確認するページ
並び、幅、比率、スクロール、作業面のどれを決めたいかで入口を選びます。
避ける使い方
レイアウトは後から中身が変わる前提で、固定値ではなく意図した制約で安定させます。
docs プレビューを成立させるためだけに固定高さを足す。
フォーム項目や入力欄を one-off styling で作り、Input 系コンポーネントを使わない。
スクロール領域とページ全体のスクロール責務を混ぜる。
まとめて使う見本
この分類のコンポーネントをまとめて、画面の骨格だけを組んだ例です。そのまま貼り付けて動きます。
import {
AspectRatio,
Badge,
Button,
Card,
CardContent,
Cluster,
Container,
Grid,
HStack,
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
ScrollArea,
VStack,
} from "@gunjo/ui";
const FILTERS = ["すべて", "要レビュー", "承認済み", "保管済み", "自分と共有"];
const TILES = [
{ id: "t1", title: "春キャンペーン", meta: "素材24点" },
{ id: "t2", title: "製品ツアー", meta: "素材8点" },
{ id: "t3", title: "料金の見直し", meta: "素材12点" },
{ id: "t4", title: "パートナー資料", meta: "素材5点" },
];
const ACTIVITY = [
"彩が「春キャンペーン」の名前を変えました",
"健が3点を承認しました",
"芽衣が「パートナー資料」を追加しました",
"翔が「第1四半期のバナー」を保管しました",
"梨奈が「製品ツアー」を共有しました",
"由紀が6点をアップロードしました",
"太郎がコメントを残しました",
"直が「第1四半期のバナー」を戻しました",
];
export function WorkspaceShell() {
return (
<Container size="lg">
<VStack gap={6}>
<HStack justify="between" wrap>
<VStack gap={1}>
<h2 className="text-xl font-semibold tracking-tight">ワークスペース</h2>
<p className="text-sm text-muted-foreground">
道具の並び、絞り込み、内容の格子、更新の記録。この4つに分けています。
</p>
</VStack>
<HStack gap={2}>
<Button variant="outline">取り込み</Button>
<Button>コレクションを作る</Button>
</HStack>
</HStack>
<Cluster gap={2}>
{FILTERS.map((filter) => (
<Badge key={filter} variant="secondary">
{filter}
</Badge>
))}
</Cluster>
<ResizablePanelGroup direction="horizontal" className="rounded-lg border">
<ResizablePanel defaultSize={68} minSize={40}>
<div className="p-4">
<Grid cols={{ base: 1, sm: 2 }} gap={4}>
{TILES.map((tile) => (
<Card key={tile.id}>
<CardContent className="space-y-3 p-3">
<AspectRatio
ratio={16 / 9}
className="overflow-hidden rounded-md bg-muted"
/>
<VStack gap={1}>
<span className="font-medium">{tile.title}</span>
<span className="text-xs text-muted-foreground">
{tile.meta}
</span>
</VStack>
</CardContent>
</Card>
))}
</Grid>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={32} minSize={22}>
<VStack gap={2} className="p-4">
<span className="text-sm font-medium">更新の記録</span>
<ScrollArea className="max-h-[220px] pr-3">
<VStack gap={2}>
{ACTIVITY.map((entry) => (
<p key={entry} className="text-sm text-muted-foreground">
{entry}
</p>
))}
</VStack>
</ScrollArea>
</VStack>
</ResizablePanel>
</ResizablePanelGroup>
</VStack>
</Container>
);
}設計の判断
レイアウトのコンポーネントをいつ使い、いつ使わないかは、UIXHERO の「UIコンポーネント完全ガイド」にある「カテゴリ 08|レイアウト・可変」の節にまとめています。要素の並べ方を決めるのか、間隔と区切りを決めるのかで、選ぶコンポーネントが変わります。
UIXHERO: UIコンポーネント完全ガイド(カテゴリ 08|レイアウト・可変)(新しいタブで開きます)