---
title: toElement - Resolve Element References for Vue 3
meta:
- name: description
  content: Resolve refs, getters, raw DOM elements, or Vue component instances to a plain DOM Element. Handles cross-version Vue Ref compatibility with structural typing.
- name: keywords
  content: toElement, transformer, element ref, DOM, component instance, resolve, TypeScript, Vue 3
features:
  category: Transformer
  label: 'E: toElement'
  github: /composables/toElement/
  level: 2
related:
  - /composables/transformers/to-array
  - /composables/transformers/to-reactive
---

# toElement

Resolves various element reference types to a plain DOM Element. Accepts refs, getters, raw DOM elements, or Vue component instances and normalizes them to a single `Element | undefined`.

<DocsPageFeatures :frontmatter />

## Usage

```ts collapse no-filename
import { toElement } from '@vuetify/v0'
import { useTemplateRef } from 'vue'

const el = useTemplateRef<HTMLDivElement>('target')

const element = toElement(el) // HTMLDivElement | undefined
```

## Architecture

`toElement` resolves multiple input shapes to a DOM element:

```mermaid "Element Resolution"
flowchart LR
  input[MaybeElementRef] --> type{"input type?"}
  type -- function --> invoke["call()"]
  type -- "{ value }" --> unwrap[".value"]
  type -- Element --> pass["pass-through"]
  type -- "null/undefined" --> undef["undefined"]
  invoke --> resolve{"is Element?"}
  unwrap --> resolve
  pass --> resolve
  resolve -- yes --> output[Element]
  resolve -- "$el" --> extract[".$el"]
  resolve -- no --> undef
  extract --> output
```

### Supported Input Types

| Input | Result |
| - | - |
| `Ref<HTMLElement>` | Unwrapped element |
| `ShallowRef<Element>` | Unwrapped element |
| `() => HTMLElement` | Called, returns element |
| `HTMLElement` / `SVGElement` | Pass-through |
| `ComponentPublicInstance` | Extracts `$el` |
| `null` / `undefined` | Returns `undefined` |

> [!TIP] Structural typing
> Uses `{ readonly value: T }` instead of Vue's nominal `Ref<T>` to avoid type mismatches across Vue versions.

## Reactivity

`toElement` is a **pure transformer function**. It does not track reactivity or return reactive values.

> [!TIP] Use inside computed for reactivity
> Wrap in `computed()` if you need reactive element resolution:
```ts
const resolved = computed(() => toElement(targetRef))
```

## Examples

::: gn-example
/composables/to-element/basic

### Source Type Resolver

An interactive resolver that passes four different input shapes to `toElement` and displays the resolved element, its tag name, and its id. The Ref button feeds a `useTemplateRef` — the most common case when working with template refs. Getter wraps the same ref in an arrow function (`() => target.value`), showing that getters are called and their return value inspected. Raw Element passes `target.value` directly — already an `HTMLElement`, so it passes through unchanged. Null demonstrates the graceful `undefined` return for absent references.

Reach for `toElement` whenever a composable or utility function accepts a flexible element source — `usePopover`, `useClickOutside`, and similar system composables all normalize their target argument through this function internally. The structural `{ readonly value: T }` typing means it accepts refs from any Vue version without nominal type mismatches. Because it is a pure synchronous call, wrap it in `toRef(() => toElement(source))` for reactive element tracking that re-resolves whenever the source changes — useful when the target ref may be `null` initially and populated after mount.

:::

## FAQ

::: faq

??? What does toElement return when given a Vue component instance?

It extracts and returns the instance's `$el`. Refs and getters are unwrapped, raw elements pass through, and `null`/`undefined` resolve to `undefined`.

??? Why does it use a structural `{ readonly value: T }` type instead of Vue's Ref?

To accept refs from any Vue version without nominal type mismatches — the structural shape matches a ref regardless of which Vue build produced it.

??? Is toElement reactive?

No. It resolves once when called. Wrap it in `toRef(() => toElement(source))` to re-resolve whenever the source ref changes — useful when a target is `null` until after mount.

:::

<DocsApi />
