Property 'X' does not exist on type 'HTMLElement' in React

avatar

Borislav Hadzhiev

Last updated: Apr 6, 2022

banner

Photo from Unsplash

Property 'X' does not exist on type 'HTMLElement' in React #

The React.js error "Property 'X' does not exist on type 'HTMLElement'" occurs when we try to access a property that doesn't exist on an element of type HTMLElement. To solve the error, use a type assertion to type the element correctly before accessing the property.

property does not exist on type htmlelement

And here are 3 examples of how the error occurs.

App.tsx
import {useEffect} from 'react'; export default function App() { useEffect(() => { const input = document.getElementById('first_name'); // ⛔️ Property 'value' does not exist on type 'HTMLElement'.ts(2339) console.log(input?.value); // ----------------------------------------------------------------- const link = document.getElementById('link'); // ⛔️ Property 'href' does not exist on type 'HTMLElement'.ts(2339) console.log(link?.href); // ----------------------------------------------------------------- const button = document.getElementById('btn'); if (button != null) { // ⛔️ Property 'disabled' does not exist on type 'HTMLElement'.ts(2339) button.disabled = true; } }, []); return ( <div> <input id="first_name" type="text" name="first_name" defaultValue="Initial Value" /> <a id="link" href="https://google.com" target="_blank" rel="noreferrer"> Open Google </a> <button id="btn">Submit</button> </div> ); }

The reason we got the error is because the return type of the document.getElementById method is HTMLElement | null and the properties we tried to access don't exist on the HTMLElement type.

To solve the error, use a type assertion to type the element correctly, e.g. as HTMLInputElement, HTMLButtonElement, HTMLAnchorElement, HTMLImageElement, HTMLDivElement, HTMLTextAreaElement, etc - depending on the type of element you are working with.

The types are consistently named as HTML***Element. Once you start typing HTML.., your IDE should be able to help you with autocomplete.

App.tsx
import {useEffect} from 'react'; export default function App() { useEffect(() => { // ✅ type elements correctly via type assertions const input = document.getElementById('first_name') as HTMLInputElement; console.log(input?.value); const link = document.getElementById('link') as HTMLAnchorElement; console.log(link?.href); const button = document.getElementById('btn') as HTMLButtonElement; if (button != null) { button.disabled = true; } }, []); return ( <div> <input id="first_name" type="text" name="first_name" defaultValue="Initial Value" /> <a id="link" href="https://google.com" target="_blank" rel="noreferrer"> Open Google </a> <button id="btn">Submit</button> </div> ); }

Type assertions are used when we have information about the type of a value that TypeScript can't know about.

We effectively tell TypeScript that the input variable stores anHTMLInputElement and not to worry about it.

Similarly, we typed the link variable to be an HTMLAnchorElement and the btn variable - HTMLButtonElement.

You can also use a type assertion inline, right before accessing a property.

App.tsx
import {useEffect} from 'react'; export default function App() { useEffect(() => { const value = (document.getElementById('first_name') as HTMLInputElement).value; console.log(value); }, []); return ( <div> <input id="first_name" type="text" name="first_name" defaultValue="Initial Value" /> <a id="link" href="https://google.com" target="_blank" rel="noreferrer"> Open Google </a> <button id="btn">Submit</button> </div> ); }

An inline type assertion gets the job done if you only need to access a property once and don't want to assign the element to a variable.

If you want to be more precise with the type of the elements, you can use a union to set the type as HTML***Element | null.

App.tsx
import {useEffect} from 'react'; export default function App() { useEffect(() => { const input = document.getElementById( 'first_name', ) as HTMLInputElement | null; console.log(input?.value); const link = document.getElementById('link') as HTMLAnchorElement | null; console.log(link?.href); const button = document.getElementById('btn') as HTMLButtonElement | null; if (button != null) { button.disabled = true; } }, []); return ( <div> <input id="first_name" type="text" name="first_name" defaultValue="Initial Value" /> <a id="link" href="https://google.com" target="_blank" rel="noreferrer"> Open Google </a> <button id="btn">Submit</button> </div> ); }

The HTML***Element or null type is the correct type, because if an element with the provided id does not exist in the DOM, the document.getElementById() method would return a null value.

You can use the optional chaining (?.) operator to short-circuit if the reference is nullish (null or undefined) right before accessing the property.

Alternatively, you can use a simple if statement that serves as a type guard, like we did with the button element.

It's always a best practice to include null in the type assertion because the getElementById method would return null if no element with the provided id was found.

Conclusion #

The React.js error "Property 'X' does not exist on type 'HTMLElement'" occurs when we try to access a property that doesn't exist on an element of type HTMLElement. To solve the error, use a type assertion to type the element correctly before accessing the property.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.