«audio» Component Type
Table of Contents
Overview
The audio type extends file and keeps its embedded file value contract, picker/drop/paste acquisition, import/export, singleton, list, and download behavior.
<audio data-smark='{"type":"audio","name":"clip"}'
controls preload="metadata"></audio>
Bare <audio data-smark> elements infer type: "audio" automatically. Unlike video, an empty audio element has no visual box, so add a singleton wrapper or companion triggers when you want an empty-state upload affordance.
Large export warning: audio values are embedded as base64. Exporting a large clip into the playground textarea serializes the entire payload and can temporarily freeze the browser. This is a limitation of displaying a large JSON/data-URL value in a textarea, not a media playback requirement. Production applications should avoid rendering multi-megabyte exports in a textarea and should submit/store the value through an appropriate binary or server-side path.
Try It
These examples use short public-domain audio excerpts (Beethoven’s 5th Symphony and Moonlight Sonata openings) so they work without a remote media host. You can replace them with your own audio in the preview. The playground’s Import button can also be used with an exported embedded value. Attribution is in docs/assets/audio-demo-attribution.md.
Basic Real Audio Field
<div id="myForm">
<strong>Clip</strong>
<audio data-smark='{"name":"clip"}' controls preload="metadata"></audio>
<button data-smark='{"action":"pick","context":"clip"}'>Choose or replace audio</button>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {"clip": "/assets/audio_beethoven_5th.mp3"}
});
👉 Try it! The <audio> element is the field itself. Because it has native controls, clicking it controls playback; use the button to upload or replace the clip.
👉 Choose an MP3, MP4/AAC, Ogg, WAV or another format your browser supports. The example starts with the opening of Beethoven’s 5th Symphony loaded by demoValue. Attribution is in the repo at docs/assets/audio-demo-attribution.md.
Singleton With An Editable Name
<div id="myForm">
<figure class="audio-card" data-smark='{"type":"audio","name":"clip"}'>
<audio data-smark controls preload="metadata"></audio>
<figcaption data-smark='{"action":"rename"}'>edit filename</figcaption>
<button data-smark='{"action":"pick"}'>Choose or replace audio</button>
<button data-smark='{"action":"download"}'>Download</button>
</figure>
</div>
#myForm .audio-card { max-width: 360px; padding: 1rem; border: 2px dashed #999; text-align: center; background: #fafafa; border-radius: .5rem; }
#myForm audio { display: block; width: 100%; }
#myForm figcaption { margin: .75rem 0; padding: .25rem; }
#myForm button { margin: .25rem; }
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {"clip": "/assets/audio_moonlight_sonata.mp3"}
});
👉 The wrapper accepts drops and pastes, while the caption edits the exported filename. Upload a clip, replace edit filename, then use Download.
👉 Native controls supplies playback; the explicit Choose or replace audio button opens the picker. SmarkForm keeps the bytes unchanged and does not transcode the audio.
👉 Initial clip: opening of Beethoven’s Moonlight Sonata. Attribution is in docs/assets/audio-demo-attribution.md.
Audio List
<div id="myForm">
<ul data-smark='{"type":"list","name":"tracks","of":"audio","min_items":0,"max_items":4}'>
<li>
<audio data-smark controls preload="metadata"></audio>
<button data-smark='{"action":"removeItem"}'>Remove</button>
</li>
</ul>
<button data-smark='{"action":"addItem","context":"tracks"}'>Add track</button>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {"tracks": [
"/assets/audio_beethoven_5th.mp3",
"/assets/audio_moonlight_sonata.mp3"
]}
});
👉 Add tracks with the list picker or drop files onto the list. Audio-capable lists append OS drops instead of replacing an existing item.
Empty-State Upload Affordance
Without native controls, the <audio> element has no visible surface. Wrap it in a singleton container to provide an empty-state label and upload affordance.
<div id="myForm">
<div class="audio-upload" data-smark='{"type":"audio","name":"clip"}'>
<audio data-smark preload="metadata"></audio>
<p class="audio-hint">Drop an audio file or click to upload</p>
<button data-smark='{"action":"pick"}'>Choose audio</button>
<button data-smark='{"action":"download"}'>Download audio</button>
<span data-smark='{"action":"rename"}'>edit filename</span>
</div>
</div>
#myForm .audio-upload { max-width: 360px; padding: 1.5rem; border: 2px dashed #999; text-align: center; background: #fafafa; border-radius: .5rem; }
#myForm .audio-hint { margin: 0 0 .75rem; }
#myForm button { margin: .25rem; }
#myForm [data-smark] { margin-right: .25rem; }
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {"clip": "/assets/audio_beethoven_5th.mp3"}
});
👉 Because the inner <audio> has no controls, the whole wrapper is the drop surface and the button opens the picker. Once a clip is loaded, use Download audio to retrieve the embedded value; add controls if you want a visible player strip.
👉 Initial clip: opening of Beethoven’s 5th Symphony. See docs/assets/audio-demo-attribution.md for attribution.
Empty State And Playback
An empty field shows an inactive <audio> element. Because an <audio> has no visual box by itself, authors who want an empty-state affordance should wrap the element in a singleton container or add companion triggers.
Use native controls when the field should be a player. Without controls, smark_audio_click: "pick" (the default when controls are absent) makes the audio surface an upload affordance. Use smark_audio_click: "play" for a programmatic player; Space toggles playback and Shift+Space still opens the picker.
<audio data-smark='{"name":"clip","smark_audio_click":"play"}'
preload="metadata"></audio>
SmarkForm does not transcode or re-encode audio. The stored value remains the original bytes; presentation is handled through the element’s src.
Keyboard And Caption Navigation
The audio itself is one SmarkForm field. Enter moves to the next field and Shift+Enter moves to the previous field. When the audio has focus:
- Space opens the picker in pick mode, or toggles playback in play mode.
- Shift+Space opens the picker even in play mode.
- Delete or Backspace clears the audio when it has a value.
The editable filename caption and trigger buttons are normal browser controls, so Tab and Shift+Tab reach them independently. Delete and Backspace edit the caption while the caption has focus; they clear the audio when the audio field itself has focus.
Validation And Options
Interactive acquisition probes the bytes with an off-DOM <audio> element and rejects malformed media silently. Set smark_audio_validate: false to disable that probe. audio_max_size rejects oversized files before reading them and dispatches a cancellable smark:audioNotice (AUDIO_TOO_LARGE); unless a listener calls preventDefault(), SmarkForm also shows an in-page toast. A malformed-media probe failure remains silent.
Common options:
acceptdefaults toaudio/*and filters picker, drop, and paste input.smark_audio_open,smark_audio_drop, andsmark_audio_pastedisable the corresponding interaction when set tofalse.smark_audio_clear_on_deletecontrolsDelete/Backspaceclearing.smark_audio_click("auto"|"pick"|"play") resolves the click/Spaceconflict."auto"defaults to play whencontrolsis present, otherwise pick.smark_audio_auto_pickopens the picker after rendering whentrue(subject to the browser’s user-gesture policy).audio_max_sizebyte cap rejects acquisition above the limit.formatandencodingare inherited fromfile.
The type does not transcode or re-encode audio. Imported values are trusted and embedded; validation applies to interactive acquisition.
Format Recommendations
For universal playback, prefer MP3 or MP4/AAC. WAV and FLAC work in all major browsers if lossless fidelity is needed. Ogg Vorbis/Opus and WebM/Opus are fine on Chromium and Firefox but may fail on Safari.
Singletons And Lists
A wrapper containing exactly one inner <audio> becomes a singleton. Mark an editable filename with the rename trigger action; SmarkForm sets contenteditable and synchronizes the stored filename automatically:
<figure data-smark='{"type":"audio","name":"clip"}'>
<audio data-smark controls preload="metadata"></audio>
<figcaption data-smark-action="rename"></figcaption>
</figure>
Lists use of: "audio" and inherit file-list acquisition and drop behavior:
<ul data-smark='{"type":"list","name":"tracks","of":"audio"}'>
<li data-smark='{"type":"audio"}'>
<audio data-smark controls preload="metadata"></audio>
</li>
</ul>
OS drops append audio items in an audio-capable list. Captions remain item-local.
When a list item is an audio field, addItem can open the picker immediately as part of the user’s add action. For a form-backed list item containing several fields, use smark_audio_auto_pick: true on the particular audio field when an automatic picker is desired. This is opt-in and browser-dependent: a picker opened after an asynchronous render may be blocked when no user gesture is active, so an explicit pick trigger remains the reliable fallback.