What Are Web Components?
Web Components are a set of browser-native APIs that let you create custom HTML elements with their own rendering, styling, and behavior — completely encapsulated from the rest of the page. They consist of three technologies: Custom Elements (defining new HTML tags), Shadow DOM (encapsulated styling and markup), and HTML Templates (reusable markup structures).
The key advantage of web components is that they work everywhere. They are not tied to a framework. A web component works in React, Vue, Angular, Svelte, Astro, plain HTML, and any other context that renders HTML. There is no build step required. No npm install. No bundler configuration. You include a script tag, and a new HTML element becomes available. This makes web components ideal for distributing embeddable widgets — and an interactive 3D viewer is a perfect use case.
The <geometry-viewer> web component encapsulates a complete 3D rendering pipeline — WebGL context, scene graph, camera controls, lighting, model loading — inside a single custom element. From the outside, it behaves like an <img> or <video> tag: you set a source, and it displays content. From the inside, it manages a full Three.js scene with orbit controls, environment lighting, and format-specific loaders.
Getting Started
The simplest possible integration requires two lines of HTML. First, include the component script from our CDN. Second, use the custom element tag with a src attribute pointing to your 3D model file.
That is it. No JavaScript to write. No initialization code. No configuration objects. The component handles model loading, camera positioning, lighting, and user interaction automatically. The model will be interactive — users can orbit, pan, and zoom using mouse or touch controls.
The component works with any model format that GeometryViewer supports: STL, OBJ, GLTF, GLB, 3MF, STEP, PLY, and FBX. The format is detected automatically from the file extension or MIME type. The src attribute accepts any URL — a path on your own server, a CDN URL, or a GeometryViewer hosted model URL.
HTML Attributes
The <geometry-viewer> element supports several attributes for controlling its behavior and appearance.
- src — URL of the 3D model to load. Required. Supports all GeometryViewer formats.
- ar — Boolean attribute. When present, shows an "View in AR" button on supported devices. On iOS, this opens AR Quick Look with a USDZ version. On Android, it opens Scene Viewer with a GLB version.
- controls — Controls visibility. Values:
"orbit"(default — orbit, pan, zoom),"turntable"(auto-rotates, user can interrupt),"none"(static view, no interaction). - wireframe — Boolean attribute. When present, renders the model in wireframe mode.
- background — Background color or style. Values: any CSS color (
"#1a1a2e"),"transparent"(for overlaying on page content), or"environment"(gradient environment map). - camera-orbit — Initial camera position as
"theta phi radius"in degrees and scene units. Example:"45deg 60deg 2.5". - environment — Lighting environment. Values:
"neutral"(default soft studio light),"bright"(strong key light),"dark"(dramatic, single light source),"outdoor"(HDR sky environment). - loading — Loading behavior. Values:
"auto"(load immediately when element is created),"lazy"(load when element enters viewport — uses IntersectionObserver),"manual"(do not load untilloadModel()is called via JavaScript).
JavaScript API
For programmatic control, the component exposes a JavaScript API on the element instance. You can get a reference to the element using standard DOM methods like document.querySelector('geometry-viewer') or, in frameworks, via refs.
Methods
- loadModel(url) — Load a new model from the given URL. Returns a Promise that resolves when the model is fully loaded and rendered. Rejects if the file cannot be loaded or parsed.
- loadBuffer(arrayBuffer, format) — Load a model from an ArrayBuffer. The
formatparameter is a file extension string ("stl","glb", etc.). Useful for loading files from drag-and-drop, clipboard, or programmatic sources without a URL. - setWireframe(enabled) — Toggle wireframe rendering. Accepts a boolean.
- resetCamera() — Reset the camera to the initial position, framing the entire model.
- screenshot() — Capture the current view as a PNG data URL. Returns a Promise that resolves with the data URL string.
- getModelInfo() — Returns an object with model metadata:
{ vertices, faces, boundingBox, fileSize, format }.
Events
- gv-loaded — Fired when a model has been successfully loaded and rendered. The event detail includes
{ format, vertices, faces }. - gv-error — Fired when a model fails to load. The event detail includes
{ message, url }. - gv-progress — Fired during model download. The event detail includes
{ loaded, total, percent }. - gv-camera-change — Fired when the user moves the camera. The event detail includes the current camera position and target. Throttled to 10 events per second to avoid performance issues.
Framework Integration
React
Web components work in React with a few considerations. React does not natively pass non-string props to custom elements as attributes — it uses properties instead. For simple string attributes like src and background, standard JSX works fine. For boolean attributes like ar, use the string "true" or conditionally include the attribute. For event listeners, use ref and addEventListener in a useEffect hook rather than onGv-loaded (React does not support hyphenated event names in JSX).
Vue
Vue has excellent web component support. Use v-bind for dynamic attributes and v-on with the .native modifier for custom events. Tell Vue's compiler to skip the custom element by adding geometry-viewer to compilerOptions.isCustomElement in your Vue config. This prevents Vue from trying to resolve it as a Vue component.
Angular
In Angular, add CUSTOM_ELEMENTS_SCHEMA to your module's schemas array. This tells Angular's template compiler to allow unknown HTML elements. Then use standard Angular binding syntax: [attr.src]="modelUrl" for attributes and (gv-loaded)="onLoaded($event)" for events.
Vanilla JS
No framework? No problem. Web components are native browser technology. Include the script tag, create the element in HTML or via document.createElement, set attributes, and add event listeners. It works exactly like any built-in HTML element.
CDN Delivery
The <geometry-viewer> component is delivered via CDN with aggressive caching. The script is under 50 KB gzipped (including the Three.js renderer and all format loaders). It loads asynchronously and does not block page rendering. For production use, pin a specific version in the script URL to prevent unexpected changes.
Performance Considerations
Each <geometry-viewer> instance creates its own WebGL context. Browsers typically limit the number of simultaneous WebGL contexts to 8-16 depending on the platform. If you need to display many models on a single page (e.g., a product catalog), use the loading="lazy" attribute so that only visible viewers create contexts. You can also use the loading="manual" attribute and programmatically control which viewers are active.
For mobile performance, keep model complexity under 100,000 triangles per viewer. Use Draco-compressed GLB files to minimize download size. Set a fixed width and height on the element to prevent layout shifts during loading. And consider using the controls="turntable" mode, which auto-rotates at a fixed speed and is less demanding than free orbit controls.
Shadow DOM and Styling
The component uses Shadow DOM for encapsulation, which means its internal styles do not leak out and your page styles do not leak in. However, you can customize certain aspects using CSS custom properties (CSS variables) that the component exposes. Set these on the <geometry-viewer> element or any ancestor. Available custom properties include --gv-loading-color (progress spinner color), --gv-button-bg (AR button background), and --gv-button-color (AR button text). The element itself can be sized with standard CSS — width, height, aspect-ratio, and responsive units all work as expected.
Accessibility
The component includes built-in accessibility features. It exposes an ARIA role of img with an aria-label derived from the filename. Keyboard users can tab to the viewer and use arrow keys for camera control. The AR button is focusable and labeled. You can override the default ARIA label by setting the alt attribute on the element, similar to how you would on an <img> tag.
Building with web components means building for the open web. No lock-in, no framework dependency, no build pipeline required. One tag, one script, and your 3D models are interactive anywhere HTML runs.