> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Layout — Sizing

> Modifiers that constrain a component's size based on aspect ratio or its ideal intrinsic size

export const PlatformStatuses = ({statuses}) => {
  const StatusBadge = ({status, label}) => {
    const styles = {
      green: {
        backgroundColor: '#dcfce7',
        color: '#166534'
      },
      orange: {
        backgroundColor: '#fed7aa',
        color: '#9a3412'
      },
      red: {
        backgroundColor: '#fecaca',
        color: '#991b1b'
      },
      gray: {
        backgroundColor: '#f3f4f6',
        color: '#4b5563'
      }
    };
    const baseStyle = {
      display: 'inline-flex',
      alignItems: 'center',
      padding: '0.125rem 0.625rem',
      borderRadius: '9999px',
      fontSize: '0.875rem',
      fontWeight: '500'
    };
    const colorStyle = styles[status] || styles.green;
    return <span style={{
      ...baseStyle,
      ...colorStyle
    }}>
        {label || status}
      </span>;
  };
  const STATUS_CONFIG = {
    supported: {
      label: "Supported",
      color: "green"
    },
    partial: {
      label: "Partial",
      color: "orange"
    },
    "not-implemented": {
      label: "Not Implemented",
      color: "gray"
    }
  };
  const renderCard = (platform, value) => {
    if (!value) return null;
    const {status, note} = typeof value === "string" ? {
      status: value
    } : value;
    const config = STATUS_CONFIG[status];
    if (!config) return null;
    const titleMap = {
      ios: "SwiftUI",
      android: "Jetpack Compose",
      web: "Web"
    };
    return <Card key={platform} title={titleMap[platform] || platform}>
          <StatusBadge status={config.color} label={config.label} />
          {note && <div style={{
      marginTop: '0.5rem',
      fontSize: '0.875rem',
      color: '#6b7280'
    }}>
              {note}
            </div>}
      </Card>;
  };
  if (statuses == null) {
    return null;
  }
  return <Columns cols="3">
      {Object.entries(statuses).map(([platform, value]) => renderCard(platform, value))}
    </Columns>;
};

export const ComposeJS = ({code, name, height}) => {
  const encodedCode = useMemo(() => {
    if (!code) return "";
    try {
      return btoa(code);
    } catch (e) {
      console.error("Failed to encode code", e);
      return "";
    }
  }, [code]);
  if (!encodedCode) {
    return null;
  }
  return <iframe src={`https://www.metabind.ai/embed?code=${encodedCode}&name=${name ?? 'Example'}`} loading="lazy" style={{
    width: "100%",
    height: height || '350px',
    border: "1px solid #e5e7eb",
    borderRadius: "var(--rounded-2xl,1rem)",
    overflow: "hidden"
  }} title="ComposeJS Preview" />;
};

These modifiers control how a component sizes itself in response to its content and the space its parent offers. `aspectRatio` constrains the width-to-height ratio. `scaledToFit` and `scaledToFill` are shorthands for the two common content modes — fit inside the frame (letterbox) or fill the frame (crop).

`fixedSize` opts a component out of the parent's size proposal entirely, using the component's ideal size instead. Useful for preventing text wrapping or letting a component report its intrinsic dimensions to its container.

## aspectRatio

Sets the aspect ratio for a component's content, controlling how it fits or fills the available space.

```typescript theme={null}
.aspectRatio(aspectRatio?: number, contentMode?: "fit" | "fill")
```

<ParamField path="aspectRatio" type="number" optional>
  The width-to-height ratio (e.g., `1.0` for square, `16/9` for widescreen). Omit to use the content's intrinsic aspect ratio.
</ParamField>

<ParamField path="contentMode" type="&#x22;fit&#x22; | &#x22;fill&#x22;" optional>
  How the content fills the frame:

  * `"fit"` — scales to fit within the frame, preserving aspect ratio (may letterbox)
  * `"fill"` — scales to fill the frame, preserving aspect ratio (may crop)
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: { status: "partial", note: "contentMode parameter is not implemented" },
web: { status: "supported" },
}}
/>

**Square aspect ratio**

```typescript theme={null}
Image({ url: "photo.jpg" })
    .resizable()
    .aspectRatio(1)
```

**Widescreen with fit**

```typescript theme={null}
Image({ url: "banner.jpg" })
    .resizable()
    .aspectRatio(16 / 9, "fit")
```

**Fill the frame**

```typescript theme={null}
Image({ url: "cover.jpg" })
    .resizable()
    .aspectRatio(4 / 3, "fill")
    .clipped()
```

**Use intrinsic ratio**

```typescript theme={null}
Image({ url: "photo.jpg" })
    .resizable()
    .aspectRatio()
```

## scaledToFit

Scales content to fit within the frame, preserving aspect ratio. May letterbox.

```typescript theme={null}
.scaledToFit(): Component
```

This modifier takes no parameters.

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: { status: "supported" },
web: { status: "supported" },
}}
/>

**Fit an image within a frame**

The image scales down to fit entirely within the frame. Empty space may appear around the content (letterboxing).

```typescript theme={null}
Image({ url: "photo.jpg" })
    .resizable()
    .scaledToFit()
    .frame({ width: 200, height: 200 })
```

**Fit inside a colored container**

```typescript theme={null}
Color("gray")
    .frame({ width: 300, height: 200 })
    .overlay(
        Image({ url: "wide-banner.jpg" })
            .resizable()
            .scaledToFit()
    )
```

## scaledToFill

Scales content to fill the frame, preserving aspect ratio. May crop.

```typescript theme={null}
.scaledToFill(): Component
```

This modifier takes no parameters.

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: { status: "supported" },
web: { status: "supported" },
}}
/>

**Fill a frame with an image**

The image scales up to fill the entire frame. Parts of the image that extend beyond the frame are cropped when combined with `.clipped()`.

```typescript theme={null}
Image({ url: "photo.jpg" })
    .resizable()
    .scaledToFill()
    .frame({ width: 200, height: 200 })
    .clipped()
```

**Comparison with scaledToFit**

`scaledToFill` ensures no empty space within the frame but may crop content. Use [scaledToFit](#scaledtofit) when you need to see the entire content.

```typescript theme={null}
HStack({ spacing: 16 }, [
    Image({ url: "wide.jpg" })
        .resizable()
        .scaledToFill()
        .frame({ width: 100, height: 100 })
        .clipped(),
    Image({ url: "wide.jpg" })
        .resizable()
        .scaledToFit()
        .frame({ width: 100, height: 100 }),
])
```

## fixedSize

Prevents a component from resizing along specified axes, using its ideal size instead.

```typescript theme={null}
.fixedSize(axes: { horizontal?: boolean; vertical?: boolean })
```

<ParamField path="axes" type="{ horizontal?: boolean; vertical?: boolean }" required>
  <Expandable title="axes">
    <ParamField path="horizontal" type="boolean" optional>
      When `true`, the component uses its ideal width and ignores the parent's width proposal.
    </ParamField>

    <ParamField path="vertical" type="boolean" optional>
      When `true`, the component uses its ideal height and ignores the parent's height proposal.
    </ParamField>
  </Expandable>
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: { status: "supported" },
web: { status: "supported" },
}}
/>

`fixedSize` tells the layout system to use the component's ideal (intrinsic) size along the specified axes, rather than the size proposed by the parent. This is useful when a parent container would otherwise compress or expand the component. For Text, this prevents line wrapping on the horizontal axis.

**Prevent text from wrapping**

```typescript theme={null}
Text("This text will not wrap to multiple lines")
    .fixedSize({ horizontal: true, vertical: false })
```

**Fixed size on both axes**

```typescript theme={null}
Text("Fixed")
    .fixedSize({ horizontal: true, vertical: true })
```

**Allow vertical expansion only**

```typescript theme={null}
Text("This text can grow taller but stays at proposed width")
    .fixedSize({ horizontal: false, vertical: true })
```

## See also

* [frame](/bindjs/modifiers/layout-frame-and-padding#frame) — sets fixed or flexible size constraints
* [layoutPriority](/bindjs/modifiers/layout-frame-and-padding#layoutpriority) — controls space distribution among siblings
* [clipped](/bindjs/modifiers/clipped) — clips content that extends past the frame
* [Image](/bindjs/components/Image) — `.resizable()` is required for image scaling modifiers
