<- Back to Content Components

Video renders a video player for module assets, runtime media URLs, proxied external URLs, or other client-safe video sources. Use it when the interface must play clips with optional title and poster artwork.

Python Contract

sdk.ui.Video(
    id: str,
    source: Any = "",
    title: Any = "",
    autoplay: bool = False,
    muted: bool = False,
    loop: bool = False,
    controls: bool = True,
    poster: Any = "",
    width: int = 640,
    height: int = 360,
)

source, title, and poster accept literal values or bindings from the constructor.

Supported Properties

Property Type Required Python YAML Notes
id str yes yes yes Stable component id
source str | binding no constructor / source.set yes Video source URL or module asset path
title str | binding no constructor / title.set yes Visible player label
autoplay bool no constructor / autoplay.set yes Starts playback automatically when allowed by the client
muted bool no constructor / muted.set yes Starts muted
loop bool no constructor / loop.set yes Replays after end of track
controls bool no constructor yes Hides or shows playback controls
poster str | binding no constructor / poster.set yes Optional image shown before playback
width int no constructor yes Default 640
height int no constructor yes Default 360
show_if rule no yes yes Generic visibility rule
hide_if rule no yes yes Generic visibility rule
required_permissions list[str] no yes yes Generic permission gate

Static Example

builder.add(
    sdk.ui.Video(
        "components_test_video_static",
        source="assets/test.mp4",
        title="Flower MP4",
        controls=True,
        width=360,
        height=210,
    )
)

Store Binding

from democrai.sdk.ui import bound

builder.add(
    sdk.ui.Video(
        "components_test_video_store",
        source=bound.store("/components_test/video/source", scope="page", default="assets/test.mp4"),
        title=bound.store("/components_test/video/title", scope="page", default="Flower MP4"),
        poster=bound.store("/components_test/video/poster", scope="page", default=""),
        controls=True,
        width=360,
        height=210,
    )
)

Data Model Binding

from democrai.sdk.ui import bound

builder.add(
    sdk.ui.Video(
        "components_test_video_data",
        source=bound.data("/components_test/video_model/source", default="assets/test.mp4"),
        title=bound.data("/components_test/video_model/title", default="Flower MP4"),
        poster=bound.data("/components_test/video_model/poster", default=""),
        controls=True,
        width=360,
        height=210,
    )
)

Direct Property Update

Declare source.set, title.set, and poster.set before an action sends direct updates to the rendered player.

builder.add(
    sdk.ui.Video(
        "components_test_video_live",
        source="assets/test.mp4",
        title="Flower MP4",
        controls=True,
        width=360,
        height=210,
    ).allow("source.set", "title.set", "poster.set")
)

builder.add(
    sdk.ui.Button(
        "components_test_video_set_alt_btn",
        "Set alternate",
        action="components.media_test_set",
        params={"component": "video", "state_key": "alternate"},
        variant="default",
    )
)

The action must target the current surface when it builds property updates:

surface_id = str(ctx.get("_surface_id") or "main").strip() or "main"
sdk.effects.ui_property_update(
    "components_test_video_live",
    "source",
    "assets/test2.mp4",
    surface_id=surface_id,
)

Visibility Rules

show_if = sdk.ui.Video(
    "components_test_video_show_if",
    source="assets/test.mp4",
    title="show_if visible",
    width=320,
    height=190,
)
show_if.set_show_if({
    "conditions": [{
        "left": bound.store("/components_test/visibility/video_show", scope="page", default=True),
        "op": "==",
        "right": True,
    }]
})
builder.add(show_if)

hide_if = sdk.ui.Video(
    "components_test_video_hide_if",
    source="assets/test.mp4",
    title="hide_if visible",
    width=320,
    height=190,
)
hide_if.set_hide_if({
    "conditions": [{
        "left": bound.store("/components_test/visibility/video_hide", scope="page", default=False),
        "op": "==",
        "right": True,
    }]
})
builder.add(hide_if)

gated = sdk.ui.Video(
    "components_test_video_required_permissions",
    source="assets/test.mp4",
    title="required_permissions gate",
    width=320,
    height=190,
)
gated.set_required_permissions(["components.media.visibility"])
builder.add(gated)

The test page updates the observed store flags with the same action used by Python and YAML declarations:

builder.add(
    sdk.ui.Button(
        "components_test_video_show_off_btn",
        "Hide show_if",
        action="components.media_test_visibility_set",
        params={"component": "video", "flag": "show", "value": False},
        variant="default",
    )
)
builder.add(
    sdk.ui.Button(
        "components_test_video_hide_on_btn",
        "Hide hide_if",
        action="components.media_test_visibility_set",
        params={"component": "video", "flag": "hide", "value": True},
        variant="default",
    )
)

Path Resolution

  • Module asset paths such as assets/test.mp4 and assets/test2.mp4 resolve to media routes for the active module.
  • assets/protected/... resolves to the same module media route but requires an authenticated user before the asset is served.
  • /media/... is already a client-facing media path and is used as-is by the clients.
  • http://... and https://... are external URLs. On web they are resolved through the media proxy when they are outside the core origin.

Usage Guidance

  • Use module asset paths for packaged video shipped with the module.
  • Use store bindings when source, title, or poster must follow page or global client state.
  • Use data model bindings when the player follows the surface data model.
  • Use runtime property updates for source, title, and poster changes without a full rerender.