> ## 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.

# Accessibility

> Modifiers that expose components to VoiceOver and other assistive technologies

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 shape how a component is announced and navigated by VoiceOver, TalkBack, and other assistive technologies. `accessibilityLabel` provides the spoken name; `accessibilityValue` adds dynamic state like a percentage; `accessibilityHidden` removes purely decorative elements from the accessibility tree; `accessibilityRemoveTraits` strips default traits like "button" or "image".

For additional context use [accessibilityHint](/bindjs/modifiers/accessibilityHint), and to add traits use [accessibilityAddTraits](/bindjs/modifiers/accessibilityAddTraits).

## accessibilityLabel

Sets the VoiceOver label for a component.

```typescript theme={null}
.accessibilityLabel(label: string)
```

<ParamField path="label" type="string" required>
  The text that VoiceOver reads when the user focuses on the component.
</ParamField>

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

**Label an icon button**

```typescript theme={null}
Button("", () => share())
    .accessibilityLabel("Share")
```

**Label an image**

```typescript theme={null}
Image({ url: "profile.jpg" })
    .resizable()
    .frame({ width: 48, height: 48 })
    .clipShape(Circle())
    .accessibilityLabel("Profile photo")
```

## accessibilityValue

Sets the current accessibility value for a component, such as a percentage or status.

```typescript theme={null}
.accessibilityValue(value: string)
```

<ParamField path="value" type="string" required>
  The current value of the component, read by VoiceOver after the label. For example, "50 percent" for a progress indicator.
</ParamField>

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

**Set a value for a progress indicator**

```typescript theme={null}
ProgressView({ value: 0.75 })
    .accessibilityLabel("Download progress")
    .accessibilityValue("75 percent")
```

**Set a value for a custom rating display**

```typescript theme={null}
HStack(stars)
    .accessibilityLabel("Rating")
    .accessibilityValue("4 out of 5 stars")
```

## accessibilityHidden

Hides a component from assistive technologies like VoiceOver.

```typescript theme={null}
.accessibilityHidden(isHidden?: boolean)
```

<ParamField path="isHidden" type="boolean" optional default="true">
  Whether to hide the component from assistive technologies. Defaults to `true`.
</ParamField>

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

**Hide a decorative element**

```typescript theme={null}
Image({ url: "decorative-divider.png" })
    .resizable()
    .accessibilityHidden()
```

**Conditionally hide from accessibility**

```typescript theme={null}
Image({ url: "icon.png" })
    .resizable()
    .accessibilityHidden(isDecorative)
```

## accessibilityRemoveTraits

Removes default accessibility traits from a component.

```typescript theme={null}
.accessibilityRemoveTraits(traits: AccessibilityTraits | AccessibilityTraits[])
```

<ParamField path="traits" type="AccessibilityTraits | AccessibilityTraits[]" required>
  One or more accessibility traits to remove from the component. See [AccessibilityTraits](/bindjs/types/AccessibilityTraits).
</ParamField>

<PlatformStatuses
  statuses={{
ios: { status: "supported" },
android: { status: "partial", note: "Clears all semantics instead of specific traits" },
web: "not-implemented",
}}
/>

**Remove the button trait from a Button used as a label**

```typescript theme={null}
Button("Status: Active", () => {})
    .accessibilityRemoveTraits("isButton")
```

**Remove multiple traits**

```typescript theme={null}
Image({ url: "photo.jpg" })
    .resizable()
    .accessibilityRemoveTraits(["isImage", "isButton"])
```

## See also

* [accessibilityHint](/bindjs/modifiers/accessibilityHint) — additional context spoken after the label
* [accessibilityAddTraits](/bindjs/modifiers/accessibilityAddTraits) — add traits like `isButton` or `isHeader`
* [accessibilityRepresentation](/bindjs/modifiers/accessibilityRepresentation) — replace the accessibility element entirely
* [AccessibilityTraits](/bindjs/types/AccessibilityTraits) — trait values
