Custom renderer in Vue 3
In this tutorial, you will create a custom cell renderer that displays image URLs as actual images in a Vue 3 application.
Overview
You can declare a custom renderer for the HotTable component by declaring it as a function in the Handsontable options or creating a rendering component.
Find out which Vue 3 versions are supported
Declare a renderer as a function
The following example is an implementation of @handsontable/vue3 with a custom renderer added. It takes an image URL as the input and renders the image in the edited cell.
import { defineComponent } from 'vue';import { HotTable } from '@handsontable/vue3';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = defineComponent({ data() { return { hotSettings: { data: [ ['A1', '/docs/img/examples/professional-javascript-developers-nicholas-zakas.jpg'], ['A2', '/docs/img/examples/javascript-the-good-parts.jpg'] ], columns: [ {}, { renderer(instance, td, row, col, prop, value) { const img = document.createElement('img');
img.src = value;
img.addEventListener('mousedown', (event) => { event.preventDefault(); });
td.innerText = ''; td.appendChild(img);
return td; } } ], colHeaders: true, rowHeights: 55, height: 'auto', autoWrapRow: true, autoWrapCol: true, licenseKey: 'non-commercial-and-evaluation' } }; }, components: { HotTable, }});
export default ExampleComponent;<div id="example1"> <hot-table :settings="hotSettings"></hot-table></div>Declare a renderer as a Vue 3 component
You can use a Vue 3 component as a custom cell renderer by mounting it into the cell’s TD element from inside the renderer function. Use Vue 3’s render(vnode, container) API to mount the component imperatively and reuse the same component instance across re-renders — Vue patches the existing tree instead of remounting.
The renderer function receives the same arguments as a regular function-based renderer. You build a VNode from your component with h(Component, props) and pass it to render() together with the TD element. To pass static props alongside cell data, merge them into the second argument of h().
import { defineComponent, h, render } from 'vue';import { HotTable } from '@handsontable/vue3';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
// A reusable Vue 3 component that renders a cell value as an image.const ImageCell = defineComponent({ props: { src: { type: String, required: true }, }, render() { return h('img', { src: this.src, onMousedown: (event) => event.preventDefault(), }); },});
// Bridge function that mounts the Vue 3 component into the cell's TD element.// Vue's `render()` patches the existing tree on subsequent calls, so the// component instance is reused across re-renders.function imageComponentRenderer(instance, td, row, col, prop, value) { const vnode = h(ImageCell, { src: value });
render(vnode, td);
return td;}
const ExampleComponent = defineComponent({ data() { return { hotSettings: { data: [ ['Professional JavaScript for Web Developers', '/docs/img/examples/professional-javascript-developers-nicholas-zakas.jpg'], ['JavaScript: The Good Parts', '/docs/img/examples/javascript-the-good-parts.jpg'], ], columns: [ {}, { renderer: imageComponentRenderer, }, ], colHeaders: true, rowHeights: 55, height: 'auto', autoWrapRow: true, autoWrapCol: true, licenseKey: 'non-commercial-and-evaluation', }, }; }, components: { HotTable, },});
export default ExampleComponent;<div id="example2"> <hot-table :settings="hotSettings"></hot-table></div>If your component needs access to a Vue application context — for example, global components, plugins, or provide / inject — create a dedicated app per cell with createApp(Component, props).mount(td) instead of render(). Track the returned app instances so you can call app.unmount() when the grid is destroyed.
Related articles
Related guides
APIs
Configuration options
Core methods
Hooks
What you learned
- How to declare a custom renderer function in a Vue 3 application.
- How to read cell values and render HTML elements — such as images — inside cells.
- How to assign the renderer to a specific column using the
rendereroption. - How to mount a Vue 3 component as a custom cell renderer with
render(vnode, td).
Next steps
- Cell renderer — explore the full renderer API.
- HotColumn component in Vue 3 — assign renderers per column declaratively.
- Custom editor in Vue 3 — pair your renderer with a custom editor.