---
title: useLayout
description: "Access dynamic layout info like viewport dimensions, theme, and visual environment in views."
---

The `useLayout` hook returns layout and visual environment information. These values may change dynamically during the session (e.g., on resize or theme toggle).

## Basic usage

```tsx
import { useLayout } from "skybridge/web";

function ThemedView() {
  const { theme, maxHeight, safeArea } = useLayout();

  return (
    <div
      style={{
        backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff",
        maxHeight,
        paddingTop: safeArea.insets.top,
      }}
    >
      <p>Current theme: {theme}</p>
    </div>
  );
}
```

## Returns

```tsx
type LayoutState = {
  theme: "light" | "dark";
  maxHeight: number | undefined;
  safeArea: SafeArea;
};
```

### `theme`

The current color theme of the host application (`"light"` or `"dark"`).

### `maxHeight`

The maximum height available for the view in pixels.

### `safeArea`

Safe area insets for devices with notches, rounded corners, or other display cutouts.

```tsx
type SafeArea = {
  insets: {
    top: number;
    right: number;
    bottom: number;
    left: number;
  };
};
```

## Examples

### Conditional Styling

```tsx
import { useLayout } from "skybridge/web";

function ThemedCard() {
  const { theme } = useLayout();
  const isDark = theme === "dark";

  return (
    <div
      style={{
        backgroundColor: isDark ? "#1a1a1a" : "#ffffff",
        color: isDark ? "#ffffff" : "#000000",
        padding: "16px",
        borderRadius: "8px",
        border: `1px solid ${isDark ? "#333" : "#e0e0e0"}`,
      }}
    >
      <h3>Themed Card</h3>
      <p>This card adapts to the current theme.</p>
    </div>
  );
}
```

### CSS Class-Based Theming

```tsx
import { useLayout } from "skybridge/web";

function View() {
  const { theme } = useLayout();

  return (
    <div className={`view ${theme === "dark" ? "dark" : "light"}`}>
      <header className="view-header">
        <h2>My View</h2>
      </header>
      <main className="view-content">
        <p>Content goes here</p>
      </main>
    </div>
  );
}
```

```css
.view {
  padding: 16px;
  border-radius: 8px;
}

.view.light {
  background-color: #ffffff;
  color: #1a1a1a;
}

.view.dark {
  background-color: #1a1a1a;
  color: #f5f5f5;
}

.view.light .view-header {
  border-bottom: 1px solid #e0e0e0;
}

.view.dark .view-header {
  border-bottom: 1px solid #333;
}
```

### CSS Variables Theme Provider

```tsx
import { useLayout } from "skybridge/web";
import { useEffect } from "react";

const lightTheme = {
  "--bg-primary": "#ffffff",
  "--bg-secondary": "#f5f5f5",
  "--text-primary": "#1a1a1a",
  "--text-secondary": "#666666",
  "--border-color": "#e0e0e0",
  "--accent-color": "#0066cc",
};

const darkTheme = {
  "--bg-primary": "#1a1a1a",
  "--bg-secondary": "#2d2d2d",
  "--text-primary": "#f5f5f5",
  "--text-secondary": "#a0a0a0",
  "--border-color": "#404040",
  "--accent-color": "#4da6ff",
};

function ThemeProvider({ children }: { children: React.ReactNode }) {
  const { theme } = useLayout();
  const variables = theme === "dark" ? darkTheme : lightTheme;

  useEffect(() => {
    const root = document.documentElement;
    Object.entries(variables).forEach(([key, value]) => {
      root.style.setProperty(key, value);
    });
  }, [theme, variables]);

  return <>{children}</>;
}
```

### Theme-Aware Chart

```tsx
import { useLayout } from "skybridge/web";

type DataPoint = {
  label: string;
  value: number;
};

function BarChart({ data }: { data: DataPoint[] }) {
  const { theme } = useLayout();
  const isDark = theme === "dark";

  const colors = {
    bar: isDark ? "#4da6ff" : "#0066cc",
    barHover: isDark ? "#80c1ff" : "#0052a3",
    grid: isDark ? "#333" : "#e0e0e0",
    text: isDark ? "#a0a0a0" : "#666666",
  };

  const maxValue = Math.max(...data.map((d) => d.value));

  return (
    <div className="bar-chart">
      {data.map((item) => (
        <div key={item.label} className="bar-container">
          <div
            className="bar"
            style={{
              width: `${(item.value / maxValue) * 100}%`,
              backgroundColor: colors.bar,
            }}
          />
          <span style={{ color: colors.text }}>{item.label}</span>
        </div>
      ))}
    </div>
  );
}
```

### Safe Area Handling

```tsx
import { useLayout } from "skybridge/web";

function FullScreenView({ children }: { children: React.ReactNode }) {
  const { safeArea, maxHeight } = useLayout();

  return (
    <div
      style={{
        maxHeight,
        paddingTop: safeArea.insets.top,
        paddingRight: safeArea.insets.right,
        paddingBottom: safeArea.insets.bottom,
        paddingLeft: safeArea.insets.left,
      }}
    >
      {children}
    </div>
  );
}
```

### Theme-Sensitive Images

```tsx
import { useLayout } from "skybridge/web";

function Logo() {
  const { theme } = useLayout();

  return (
    <img
      src={theme === "dark" ? "/logo-light.svg" : "/logo-dark.svg"}
      alt="Logo"
      className="logo"
    />
  );
}
```
