Specialized inputs

AppFileAttachment

A compact browse row that swaps to a thumbnail (or file-type icon) + filename/size — one file or many.

<app-file-attachment name="doc" label="Ticket attachment" />

<app-file-attachment> attaches a file to something — a ticket, a message, a comment — where the file's name and size matter more than a big preview. It shows a slim browse row that swaps to a preview (an image thumbnail, or a file-type icon for PDFs and other documents) plus the filename and size once a file is chosen (× to remove). Add multiple="true" to let several files stack in a list, each removable on its own.

Its look comes entirely from the shared @webority/theme, so the Razor <app-file-attachment> and the React <AppFileAttachment> render identically on every Webority surface. Never hand-roll a raw <input type="file">.

Playground

Every meaningful attribute, live. Each change re-renders the real tag helper on the server; pick or reject a file in the row below to see the same client-side thumbnail/icon swap and validation error React shows.

<app-file-attachment name="pgAttachment" />
Built-in validation shows the same way as the error attributePick a file outside accept or over max-size-mb and the field shows its own rejection message below the row — the same .field-error spot the error attribute uses. The two never show at once; a fresh pick clears whichever is showing.

The attach row

Empty, the field is a compact row with a browse affordance. Pick a file to see it swap to a thumbnail + name + size.

Browse → thumbnail + name
The field is controlled — the parent owns the chosen file. Type and size are validated before the choice is reported, and the preview is managed for you.
Show code
<app-file-attachment name="ticketAttachment" label="Ticket attachment" optional="true" />
Compact, not a showcaseReach for this when the file is evidence attached to a record — the row stays out of the way and reports what's attached. When the picture itself is the point and the user should see it large, use AppFilePicker instead.

Accepted types

Narrow the accepted types to the formats you handle; the field enforces type and size before it reports the choice, and a rejected file shows an inline message.

PNG/JPG only
Restricting the accepted formats keeps the picker to what your backend can store; the hint reflects the limit.
Show code
<app-file-attachment name="ticketAttachment" label="Ticket attachment" accept="image/png,image/jpeg" optional="true" />

Multiple & file types

Widen accept beyond images and the row accepts any type — a non-image file shows a file-type icon instead of a thumbnail. Add multiple="true" and picked files stack in a list, each with its own × to remove.

Multiple files, mixed types
Each pick appends to the list (duplicates by name+size are ignored). Images render a thumbnail; PDFs and other files render a file-type icon. A single image still gets the full-width preview.
Show code
<app-file-attachment name="attachments" label="Attachments" multiple="true" accept="image/png,image/jpeg,application/pdf" optional="true" />

Optional & errors

Mark the field optional to add an “(optional)” hint beside the label, and pass an error to surface a submit-time problem below the row in the field's error style.

Optional, and a submit-time error
The “(optional)” hint tells the user the attachment can be skipped; an error message sits below the row in the standard field-error style when a value is required but missing.
File is required
Show code
<app-file-attachment name="ticketAttachment" label="Ticket attachment" optional="true" />
<app-file-attachment name="photo" label="Photo" error="File is required" />

When to use

Use it when

  • A file is attached to a record — a ticket, a message, a comment — as evidence.
  • The filename and size matter more than seeing the picture large.
  • You want type + size validation and preview handling done for you in a compact row.

Reach for something else when

  • The image is the star and the user should see it large. → AppFilePicker
  • The upload is a round avatar or a company logo. → AppLogoPicker
  • It is a plain text or number field, not a file. → AppInput
  • You hand-roll a raw <input type="file"> with custom markup. → AppFileAttachment

Best practices

Do
Give the row a specific label and restrict the accepted types, so the user knows what belongs here and what’s allowed before they pick.
Don't
A bare "Attach" label with no constraints leaves the user unsure what belongs here or what the field accepts.
Do
File is required
Surface a submit-time requirement with a message below the row, in the field’s error style.
Don't
Marking a genuinely required attachment "optional" mis-signals that it can be skipped.

Every option

The whole surface of the component, one cell per case. The tag helper has no value attribute — a picked-file preview only exists after a real client-side pick (webority-ui.js), so the preview/size/multiple groups below hand-write that same markup as a static illustration; every other group renders the real <app-file-attachment>.

preview — image thumbnail vs file-type icon

picked: image — big preview, single mode (static illustration)
brand-hero.png
brand-hero.png
212 KB
picked: non-image — compact row, file-text icon (static illustration)
quarterly-report.pdf884 KB
existing { url, name }, accept=image-only — treated as an image (static illustration)
brand-mark.png
brand-mark.png
existing { url, name }, accept=mixed — judged by name, file-text icon (static illustration)
contract.pdf

size / meta line

a picked file — size shown (static illustration)
quarterly-report.pdf884 KB
an already-attached file — no size line (size unknown) (static illustration)
contract.pdf

multiple — stacked list, each with its own remove

multiple, mixed image + non-image files (static illustration)
brand-hero.png brand-hero.png212 KB
quarterly-report.pdf884 KB
scope.docx44 KB

states

(default) — empty, required
optional="true" — empty
error="File is required" — no value
File is required
error — alongside a picked file (static illustration)
brand-hero.png
brand-hero.png
212 KB
This photo failed the server-side check

accept — every hint variant

accept="image/png,image/jpeg,image/webp"
accept="image/png,image/jpeg"
accept="image/png,image/jpeg,application/pdf"
accept="application/pdf"

Attributes

AttributeTypeDefaultDescription
namestring—Form field name for the posted file input.
labelstringAttachmentField label shown above the row.
acceptstringimage/png,image/jpeg,image/webpComma-separated MIME/extension allowlist. Widen it (e.g. image/*,application/pdf) to accept non-image files. An empty value accepts any file type, and the hint then names no types.
multipleboolfalseAccept several files at once — they stack in a list, each removable on its own.
optionalboolfalseAdds an “(optional)” hint beside the label.
errorstring—Error message shown below the row, in the field-error style.
max-size-mbint5Maximum accepted file size in MB (React maxSizeMb). Unset means 5. 0 or less means no size limit, and the hint then names no size.
validatebooltrueCheck each pick against accept and max-size-mb in the browser and show the field's own message for a rejected file. Set false when the page validates the files and shows its own message through error, so one problem never gets two messages. The limits still set the picker filter and the hint.
value——React-only. The tag helper has no value input — a picked file only exists as client-side state (webority-ui.js) after the user interacts with the row; there is no way to pre-render an already-attached file from the server.