Osy#betaa language · its runtime Osyrin · a hosted platform
Why Osy#Built for agentsAgents as declarationsWorkflows that waitRuns exactly onceSecure by defaultNothing to mockThe editor is the compilerUI in the languageDocuments are dataOne program

Reference / UI

upload

Upload(onUploaded: Ingest) { …your own content… } · Upload(accept: "image/*", onUploaded: Ingest) — a file picker whose action receives an UploadedFile

`Upload(onUploaded: Ingest) { … }` is a file picker wearing whatever you put inside it. When someone chooses a file its bytes are stored and your action receives an `UploadedFile` — the path they landed at, plus the name, type and size the browser reported. The bytes never pass through your code.

previewuifilesstorageforms

Summary#

Upload is a file picker you supply the appearance of. Put anything inside it — a button, a row with an icon, a whole drop zone — and it becomes the thing a person clicks to choose a file.

When they choose one, the bytes are stored and your action is called with an UploadedFile:

fieldwhat it is
Pathwhere the bytes were stored. This is the value you keep.
FileNamethe original name the browser reported
ContentTypethe type the browser reported
Lengththe size in bytes, as the browser reported it

The same value comes back from camera and microphone's Camera.Capture() and both StopRecording()s, so one Ingest(UploadedFile f) serves a chosen file and a photograph alike.

Signature#

Upload(onUploaded: Ingest) { Text("Choose a file"); }     // your own content is the button
Upload(accept: "image/*", onUploaded: Ingest) { … }       // narrow what the picker offers

Description#

The content inside it IS the button#

There is no built-in appearance to override. Whatever you render inside the Upload is what a person sees and clicks — so it takes your icons, your spacing and your variants like anything else.

[Composable] component UploadButton(Action<UploadedFile> onUploaded) {
  variants {
    base { Display = Display.InlineFlex; H = "32px"; Px = 3; Bg = Colors.Primary; Color = Colors.OnPrimary; Rounded = Radius.Md;
           FontSize = FontSize.Body; FontWeight = FontWeight.Semibold; WhiteSpace = WhiteSpace.Nowrap; Transition = Motion.Fast; }
  }
  render {
    Upload(onUploaded: onUploaded) {
      Row(gap: 2, align: Align.Center, justify: Justify.Center) { Icon(Icons.Upload, size: 18); Text("Upload"); }
    }
  }
}

The bytes never reach your code#

By the time your action runs, the file is already stored. You receive a path, not a buffer — so a 9 MB photograph costs your action nothing, and there is no way to accidentally hold one in a field.

What you do with the path is the interesting part: usually build a FileAsset from it, which is what gives the file an owner, grants, deduplication and a quota. demo/file-manager is the worked version.

What may be uploaded#

Images, audio, video, and a few text formats (text/plain, text/markdown, text/csv, application/json). The limit is 10 MB per file.

SVG is deliberately refused, even though it is an image. An SVG is a document that can carry script, so a stored one served back from your own origin is a cross-site-scripting vector; every other image format is inert. If you want vector art in your app, ship it as an asset instead — see textures for which folder each kind of art belongs in.

Uploading is an authorized act#

The file store accepts writes from a signed-in user. An app with no users can show a picker and keep nothing — and the refusal arrives as an error your action can catch and report, not as a silent nothing.

This is the same rule camera and microphone runs into, and for the same reason: a file that arrives from a browser has an owner, and an app with no users has nobody to be one.

accept: narrows the picker, it does not enforce anything#

accept: "image/*" tells the browser which files to offer by default. It is a convenience for the person choosing, not a guarantee — the server decides what it will actually store, and refuses everything outside the list above.

See also#

Related

camera and microphone

Take a photograph, record a video, or record audio. `Camera.Start()` asks for the device and `Camera()` shows the…

Files (addressing something the app stores)

The platform stores a file two ways, and which one you hold decides how you address it. A PATH-keyed file lives at an…

component

The one archetype for all UI: a bounded reactive unit — typed props, reactive members (fields, `live`…

textures

Drop `.png`, `.jpg` or `.webp` files into `model/textures/` and blit them onto a canvas with `Draw.Image(wall, …)`. The…