Skip to main content

The material-viewer element

This is a live <material-viewer> showing copper under neutral studio lighting. Drag to orbit, scroll to zoom, and click the gear for settings.

<material-viewer> is a web component for .mtlx and .mtlx.zip materials. It works in plain HTML and any framework, with no React dependency or build step.

Add it to a page​

Load the self-contained JavaScript bundle from jsDelivr, then add the element:

<script type="module" src="https://cdn.jsdelivr.net/npm/mtlx-viewer/dist/material-viewer.js"></script>
<material-viewer
src="https://mtlx.ben3d.ca/materials/copper/copper.mtlx"
alt="Copper material under neutral studio lighting"
settings-panel="closed"
style="display:block;width:100%;height:440px"
></material-viewer>

The unversioned URL follows the latest published npm release, subject to CDN and browser caching. To pin a release, insert its exact version after the package name: mtlx-viewer@<version>/dist/material-viewer.js.

The bundle includes Three.js and the viewer code; no separate stylesheet or framework is needed. The element defaults to 440px tall; override its size with CSS. Serve your material and textures over HTTP(S). Resources on another origin must allow CORS. A .mtlx.zip can carry the document and textures together.

Rendering needs a real GPU-backed WebGPU or WebGL2 context. Preview support follows Three.js's MaterialX loader, so some valid MaterialX nodes may not render.

With npm or a bundler​

npm install mtlx-viewer three
import 'mtlx-viewer/element';

Then use the same HTML element. This import registers the element and uses your installed Three.js; React is optional. For self-hosting without a bundler, copy node_modules/mtlx-viewer/dist/material-viewer.js to your public directory and point the script tag at it.

For React applications, see the React wrapper and viewer integration guide.

Attributes​

This reference follows repository main. Published npm releases can have fewer attributes or methods; the CDN always serves a published release. To try unreleased features, use the bundle built with this site or build the repository locally.

AttributeBehavior
srcURL to a loose .mtlx or .mtlx.zip package
altAccessible description; changes update the current preview without reloading
geometrytotem, sphere, cube, plane, or custom with model
materialInitial material name; defaults to the document’s last material
modelCustom glTF/GLB preview model URL
iblstudio (default), bridge, or a custom HDR/EXR/PNG/JPEG URL
backgroundwhite (default), environment, or none
environment-rotationLighting yaw in degrees, normalized to [0, 360)
camera-orbitAzimuth, polar angle, and radius, for example 30deg 65deg 2m
camera-targetCamera aim point in normalized scene meters, for example 0m 0m 0m
field-of-viewVertical field of view in degrees
settings-panelhidden (default) hides panel and gear; closed shows the gear; open shows the panel
rotate, bloom, aoSet to "false" to disable
tone-mappingneutral (default), aces, agx, reinhard, cineon, linear, or none
exposure, intensityExposure in EV and environment intensity
animationplay, pause, or false to hide the material-animation control
errorssilent hides the overlay; error events still fire

The built-in progress bar appears automatically during setup and updates. Customize --progress-bar-color, --progress-bar-height, or provide a slot="progress-bar" replacement. An empty replacement slot hides it.

Events and JavaScript​

Wait for registration before calling element methods. Listen for events to integrate with your own UI:

await customElements.whenDefined('material-viewer');
const viewer = document.querySelector('material-viewer');
viewer.addEventListener('load', () => console.log('Material ready'));
viewer.addEventListener('error', (event) => console.error(event.detail));
viewer.addEventListener('progress', (event) => console.log(event.detail.totalProgress));
viewer.addEventListener('camera-change', (event) => console.log(event.detail));
viewer.setAttribute('geometry', 'sphere');

The component dispatches load, error, progress, and camera-change events. Use getCameraSettings() to read current framing after load. Source and custom-model changes reload the preview; inspection settings update it in place.

For a simple chromeless iframe, use /embed?materialUrl=<encoded-material-url>. The viewer's Share menu generates viewer, embed, and iframe links with the current framing and rendering choices.

Screenshot export​

The standalone element and shared viewer expose toBlob(options?). Capture PNG, JPEG, or WebP with explicit dimensions and a white, environment, or transparent backdrop. Captures wait for current resources and GPU rendering and preserve the on-screen viewport.

const viewer = document.querySelector('material-viewer');
const blob = await viewer.toBlob({
width: 1200,
height: 800,
background: 'white',
mimeType: 'image/png',
});
const url = URL.createObjectURL(blob);
const download = document.createElement('a');
download.href = url;
download.download = 'material.png';
download.click();
URL.revokeObjectURL(url);

The React wrapper accepts a typed ref to the custom element. The online viewer also has a Download screenshot button. Source replacement or disposal cancels obsolete captures; see the generated viewer API for option and error details.