embedding a web page¶
load a URL inside rounded clipped corners, pause it, and hide it without killing the panel
by the end of this guide you will have a panel that renders a live web page inside a rounded clip wrapper, a button that pauses and resumes the page, and a second button that unmounts and remounts the whole webview so the frame is gone when you do not need it.
the webpanel blob¶
goo wraps the engine Chromium webview in a blob called WebPanel. you give it a Url and a size; it renders the page as part of your layout tree.
create Code/MyUI/WebEmbedUI.cs:
using Goo;
using Sandbox.UI;
namespace Sandbox;
public class WebEmbedUI : GooPanel<Container>
{
protected override Container Build() => new Container
{
Padding = 24,
BackgroundColor = Color.Black.WithAlpha( 0.7f ),
BorderRadius = 16,
Children =
{
new Goo.WebPanel
{
Url = "https://google.com/",
Width = 640,
Height = 420,
},
},
};
}
press play and mount WebEmbedUI on a screen panel. the page loads in place, laid out like any other blob.
rounding the corners¶
WebPanel does not expose BorderRadius or Overflow. the webview owns its own paint surface, so corner clipping has to come from a wrapping Container. set Overflow = OverflowMode.Hidden on the wrapper and the corners clip the page correctly.
protected override Container Build() => new Container
{
Padding = 24,
BackgroundColor = Color.Black.WithAlpha( 0.7f ),
BorderRadius = 16,
Children =
{
new Container
{
Key = "web-wrap",
BorderRadius = 12,
Overflow = OverflowMode.Hidden,
Width = 640,
Height = 420,
Children =
{
new Goo.WebPanel
{
Url = "https://google.com/",
Width = Length.Percent( 100 ),
Height = Length.Percent( 100 ),
},
},
},
},
};
the inner wrapper at BorderRadius = 12 plus Overflow = OverflowMode.Hidden does the actual clipping work on the webview.
pausing the page¶
a live webview ticks JavaScript, repaints, and runs media even when nothing is visible. Paused = true throttles all of that. the approach is a _paused field on the class, a button that flips it and calls Rebuild(), and the field fed directly into Paused on each build.
public class WebEmbedUI : GooPanel<Container>
{
bool _paused;
protected override Container Build() => new Container
{
Padding = 24,
BackgroundColor = Color.Black.WithAlpha( 0.7f ),
BorderRadius = 16,
Gap = 12,
Children =
{
new Container
{
Children =
{
new Container
{
Padding = new Length( 6, 14 ),
BackgroundColor = Color.FromRgb( 0x2563eb ),
HoverBackgroundColor = Color.FromRgb( 0x1d4ed8 ),
BorderRadius = 6,
OnClick = e => { _paused = !_paused; Rebuild(); },
Children = { new Text( _paused ? "resume" : "pause" ) },
},
},
},
new Container
{
Key = "web-wrap",
BorderRadius = 12,
Overflow = OverflowMode.Hidden,
Width = 640,
Height = 420,
Children =
{
new Goo.WebPanel
{
Url = "https://google.com/",
Paused = _paused,
Width = Length.Percent( 100 ),
Height = Length.Percent( 100 ),
},
},
},
},
};
}
click pause and the page goes quiet; click resume and it picks back up.
hiding and showing with unmount¶
hiding the wrapper with Opacity = 0 leaves the webview running silently. to actually stop it consuming resources, pull it out of the tree entirely. a _visible field controls whether the wrapper slot has a child. when _visible is false the slot is an empty Container and the webview is gone; when it flips back the reconciler creates a fresh one.
here is the complete class with both controls:
public class WebEmbedUI : GooPanel<Container>
{
bool _paused;
bool _visible = true;
protected override Container Build() => new Container
{
Padding = 24,
BackgroundColor = Color.Black.WithAlpha( 0.7f ),
BorderRadius = 16,
Gap = 12,
Children =
{
new Container
{
FlexDirection = FlexDirection.Row,
Gap = 8,
Children =
{
new Container
{
Padding = new Length( 6, 14 ),
BackgroundColor = Color.FromRgb( 0x2563eb ),
HoverBackgroundColor = Color.FromRgb( 0x1d4ed8 ),
BorderRadius = 6,
OnClick = e => { _paused = !_paused; Rebuild(); },
Children = { new Text( _paused ? "resume" : "pause" ) },
},
new Container
{
Padding = new Length( 6, 14 ),
BackgroundColor = Color.FromRgb( 0x4b5563 ),
HoverBackgroundColor = Color.FromRgb( 0x374151 ),
BorderRadius = 6,
OnClick = e => { _visible = !_visible; Rebuild(); },
Children = { new Text( _visible ? "hide" : "show" ) },
},
},
},
new Container
{
Key = "web-slot",
Children =
{
_visible
? new Container
{
Key = "web-wrap",
BorderRadius = 12,
Overflow = OverflowMode.Hidden,
Width = 640,
Height = 420,
Children =
{
new Goo.WebPanel
{
Url = "https://google.com/",
Paused = _paused,
Width = Length.Percent( 100 ),
Height = Length.Percent( 100 ),
},
},
}
: null,
},
},
},
};
}
the Key = "web-slot" container is always present so the surrounding layout does not shift. only its child appears and disappears. (how Key drives structural diffing is covered in build method.)
what just happened¶
three ideas were layered, each building on the last:
WebPanelwith aUrlis enough to render a live page. size it the same way you size any blob.WebPaneldoes not clip its own corners. aContainerwithBorderRadiusandOverflow = OverflowMode.Hiddenwraps it and does the clipping.Paused = truethrottles the webview without removing it. if you want to stop it completely, omit it from the tree by gating on a_visiblefield. both are valid; use whichever matches the use case.
the probe this guide is based on lives in Code/Demo/DocsProbes/DocsWebProbeUI.cs if you want to see the same ideas exercised with the kit controls.
see also¶
- webpanel guidance - full property table, the wrapper pattern for container-only styles, and the pause pattern explained.
- build method - how
Rebuild()schedules a freshBuild()and howKeydrives structural diffing. - container reference - the full layout and style surface for
Container, includingOverflowandBorderRadius. - styles - the wrapper pattern for all engine-special blobs that expose a smaller style surface than
Container.