Skip to main content
.visualEffect(callback: (builder: VisualEffectBuilder, proxy: GeometryProxy) => VisualEffectBuilder): Component
callback
(builder: VisualEffectBuilder, proxy: GeometryProxy) => VisualEffectBuilder
required
A function that receives a VisualEffectBuilder and a GeometryProxy, and returns the builder with effects chained onto it. The proxy provides layout information (size, position, safe area insets) that can drive the effect values.

VisualEffectBuilder Methods

The builder supports the following chainable methods:
  • blur(radius) — applies a Gaussian blur
  • opacity(amount) — sets opacity (0 to 1)
  • offset({ x, y }) — offsets the component
  • scale(value) or scale({ x, y }) — scales uniformly or per-axis
  • transform(matrix) — applies a full 2D affine transform
  • translation({ x, y }) — translates the component
  • rotation(degrees), rotation({ degrees }), or rotation({ radians }) — rotates the component

GeometryProxy Properties

The proxy provides layout information about the component:
  • size{ width, height } of the component
  • safeAreaInsets{ top, leading, bottom, trailing }
  • frame(coordinateSpace) — returns a GeometryRect with minX, minY, maxX, maxY, width, height, midX, midY
  • bounds(coordinateSpace) — returns the bounds of a named coordinate space
Available coordinate spaces: "global", "local", "scrollView", or a custom name registered via .coordinateSpace().

Support

Usage

Scroll-driven opacity

Fade a component based on its position within a scroll view.
Text("Fading text")
    .visualEffect((builder, proxy) =>
        builder.opacity(
            proxy.frame("scrollView").minY > 0 ? 1 : 0.3
        )
    )

Parallax effect

Image({ url: "banner.jpg" })
    .resizable()
    .scaledToFill()
    .frame({ height: 300 })
    .clipped()
    .visualEffect((builder, proxy) =>
        builder.offset({
            x: 0,
            y: proxy.frame("scrollView").minY * 0.5
        })
    )

Scale and blur on scroll

Text("Hero Title")
    .font("largeTitle")
    .visualEffect((builder, proxy) => {
        const scrollY = proxy.frame("scrollView").minY
        return builder
            .scale(scrollY > 0 ? 1 + scrollY / 500 : 1)
            .blur(scrollY < 0 ? -scrollY / 10 : 0)
    })

Size-based rotation

Rectangle()
    .frame({ width: 100, height: 100 })
    .foregroundStyle(Color("blue"))
    .visualEffect((builder, proxy) =>
        builder.rotation(proxy.size.width > 100 ? 45 : 0)
    )

Notes

  • The callback is re-evaluated whenever the component’s geometry changes (e.g., during scrolling or resizing).
  • Effects applied through the builder do not affect the component’s layout. They are purely visual transforms.
  • Use .coordinateSpace() on a parent to create named coordinate spaces that can be referenced in proxy.frame().

See Also