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

# OpenURLAction

> Intercepts URL-opening requests for custom handling via the environment system.

```typescript theme={null}
OpenURLAction(callback: (url: string) => OpenURLActionResult | void): Component;
```

<ParamField path="callback" type="(url: string) => OpenURLActionResult | void" required>
  A function that receives a URL string and returns a result indicating how the URL should be handled. Returning `void` is treated the same as `{ systemAction: true }`.
</ParamField>

## Returns

A `Component` value that is passed to `.environment("openURL", ...)` to intercept URL requests in the subtree.

## Result Types

The callback can return one of these `OpenURLActionResult` values:

<ParamField path="{ handled: true }" type="object">
  The URL was handled by your custom logic. No further action is taken.
</ParamField>

<ParamField path="{ discarded: true }" type="object">
  The URL should be ignored entirely.
</ParamField>

<ParamField path="{ systemAction: true }" type="object">
  Delegate to the platform's default URL handler.
</ParamField>

<ParamField path="{ systemAction: { url, preferInApp? } }" type="object">
  Open a (possibly rewritten) URL. Set `preferInApp` to `true` to suggest an in-app browser.
</ParamField>

## Usage

### Custom scheme handling

```typescript theme={null}
const body = () => {
    const navigate = useNavigate()

    return VStack([
        Markdown(props.content)
    ]).environment("openURL", OpenURLAction((url) => {
        if (url.startsWith("myapp://")) {
            navigate({ to: "deep-link", props: { url } })
            return { handled: true }
        }
        return { systemAction: true }
    }))
}
```

### Open external URLs in-app

```typescript theme={null}
const body = () => {
    return VStack([
        Markdown(props.content)
    ]).environment("openURL", OpenURLAction((url) => {
        return {
            systemAction: {
                url,
                preferInApp: true
            }
        }
    }))
}
```

### Block certain domains

```typescript theme={null}
const body = () => {
    return VStack([
        Markdown(props.content)
    ]).environment("openURL", OpenURLAction((url) => {
        if (url.includes("blocked-site.com")) {
            return { discarded: true }
        }
        return { systemAction: true }
    }))
}
```

### URL rewriting

```typescript theme={null}
const body = () => {
    return VStack([
        Markdown(props.content)
    ]).environment("openURL", OpenURLAction((url) => {
        if (url.startsWith("http://")) {
            return {
                systemAction: {
                    url: url.replace("http://", "https://"),
                    preferInApp: true
                }
            }
        }
        return { systemAction: true }
    }))
}
```

## Notes

* The action is set via `.environment("openURL", ...)` and applies to all child components in the subtree.
* Returning `void` (no return value) is treated the same as `{ systemAction: true }`.
* The `preferInApp` option is a hint to the platform. Not all platforms support in-app browsers.
* The callback is synchronous. Use state updates or actions for async side effects.
* URL validation is your responsibility -- the system does not validate URLs before calling your handler.

## See Also

* [useEnvironment](/bindjs/functions/useEnvironment) -- access environment values including `openURL`
