Skip to content

Widget clipping and layering

Loading interactive example…Open in new tab ↗
Opening the live canvas…

The controls card extends beyond its clipping frame. A higher element covers part of the live controls. Hidden and covered controls must not receive pointer input; the visible foreground element owns that space.

ActionPublic APIExpected result
Move framemoveElements(['frame'], delta)Moves the child once with its owner; the independent cover stays in place.
Remove coverremoveElements(['cover'])Reveals controls beneath it.
Release contentsremoveFrames()Removes the selected frame, retaining the widget and its world position.
Undoundo()Restores the prior ownership, clipping or cover.

Try dragging the cover, clicking the visible slider, and releasing the contents to reveal the bottom of the widget. Pan and zoom through the normal canvas controls. The example supplies canonical ownership and z-order; the framework owns widget mounting, clipping, hit testing and transforms.

The bottom Count button is fully outside the frame and is omitted from the accessibility tree. Releasing the contents exposes it again. Partially visible controls retain their accessibility nodes; clipping follows the resolved path's bounding rectangle for native semantics, while pointer clipping uses the path.

Source

dart
DrawingSession widgetLayersSession() {
  final seed = createControlsExample();
  try {
    return DrawingSession(
      shapeRegistry: controlsExampleRegistry(),
      configuration: seed.canvasConfiguration,
      document: DiagramDocument(
        id: 'widget-layers',
        revision: 0,
        elements: [
          ShapeElement(
            id: 'frame',
            type: Shapes.frame,
            frame: const DiagramRect.fromLTWH(0, 0, 340, 180),
            clipContent: true,
          ),
          seed.document
              .shapeById('controls')!
              .copyWith(
                parentId: 'frame',
                frame: const DiagramRect.fromLTWH(60, 0, 300, 280),
                zIndex: 1,
              ),
          ShapeElement(
            id: 'cover',
            type: Shapes.rectangle,
            zIndex: 2,
            frame: const DiagramRect.fromLTWH(180, 80, 170, 80),
            style: const ShapeStyle(
              fill: DiagramColor(0xFFE4E4E7),
              cornerRadius: 8,
            ),
            textStory: TextStory.paragraph(
              id: 'cover-story',
              blockId: 'cover-text',
              text: 'On top of the controls',
            ),
          ),
        ],
      ),
    );
  } finally {
    seed.dispose();
  }
}