Skip to content

Asset Pickers — Browse Assets Only

Widget editors must not let authors paste external URLs directly. The asset library is the single point of ingestion for any external URL (YouTube, Vimeo, S3, CDN-hosted images, etc.). Authors register the URL there once and then pick it through Browse Assets.

This rule applies to images, audio, video, downloadable files — anything an author would otherwise want to "paste a link into." It does not apply to learner-facing URL fields that point at non-asset destinations (e.g. external website redirects, link metadata).

Required pattern

Use the shared MediaField component for every asset slot:

<MediaField
  value={content.imageUrl}
  onChange={(url) => updateContent({ imageUrl: url })}
  accept={["images"]}
  label={t("imageLabel")}
  testId="widget-<type>-image"
/>

MediaField only renders a "Browse Assets" button — there is no allowExternalUrl prop, no toggle, no URL input. The browse flow opens AssetPickerDialog, which is the only entry point for external URLs.

Forbidden

  • A plain <Input type="url"> field for an asset URL in a widget editor.
  • Re-introducing an allowExternalUrl prop, URL toggle, or URL input on MediaField or a sibling component.
  • A per-widget free-form URL field that bypasses the asset library (e.g. "Paste a YouTube link here").
  • Bypassing MediaField and rolling your own browse-vs-paste UI.

Allowed

  • Non-asset URL fields (learner-facing redirect URLs, external website embeds, link metadata) authored through plain <Input> — these never become an asset.
  • The asset library's own URL-registration screen — it remains the canonical URL ingestion point.
  • Capturing per-widget metadata (filename, size, mime) via MediaField's onAssetSelect callback.

Test expectations

  • Tests that stub MediaField must not surface a data-allow-external-url attribute (the prop no longer exists). Existing assertions that depend on it should be deleted.
  • A new MediaField widget should have a regression test that *-url-toggle and *-url-input testids are never rendered.