Cannot find name "offsetHeight" or "clientHeight" on a React/Next.js TypeScript project

Viewed 92

I have a custom collapsible FAQ component that is based on the height of the element when it's expanded and vice versa.

import { useState, useRef, useEffect } from "react";

export default FAQItem({title, description}: FAQItemProps) {
  const [isOpen, setIsOpen] = useState(false);
  const heightRef = useRef<HTMLDivElement>(null);

  const collapsible = () => (!isOpen ? setIsOpen(true) : setIsOpen(false));
  
  useEffect(() => {
    !isOpen
      ? (heightRef.current!.style.height = "96px")
      : (heightRef.current!.style.height = `${offsetHeight}px`)
  }, [isOpen]);

  return(
    <div ref={heightRef}>
      <h2 onClick={collapsible}>{title}</h2>
      <p>{description}</p>
    </div>
  )
}

Because I'm dealing with TypeScript, some of the already answered solutions I could find unfortunately doesn't have anything TypeScript-related answered and won't fly with TS and had to add type definitions. And it returned with error Cannot find name "offsetHeight"., and clientHeight does the same thing too.

I've tried adding any to offsetHeight, including:

declare const window: Window & typeof globalThis & {
  offsetHeight: number | any;
}

...and as expected, the error went away but it didn't work - the height didn't change and and won't expand.

Nevertheless, all the solutions I could find unfortunately has no TypeScript-related answers regarding getting the width or height of an element on a React TypeScript project - all of them are just plain React questions without TypeScript, and I prefer to not use any external libraries of any kind either.

2 Answers

The reason you are getting the error is because you haven't defined the variables offsetHeight and clientHeight. Now, I know you don't need to define them, but because your usage is improper, the compiler thinks you forgot to create these variables.

Here's what you want: heightRef.current?.clientHeight and heightRef.current?.offsetHeight, the ? is just to avoid errors in case the ref is not loaded.

Edit with code

import "./styles.css";
import React from "react";

export default function App() {
  const [isOpen, setIsOpen] = React.useState(false);
  const heightRef = React.useRef<HTMLDivElement>(null);

  const collapsible = () => setIsOpen(!isOpen);

  console.log(isOpen, heightRef.current?.style?.height);

  React.useLayoutEffect(() => {
    if (isOpen) {
      heightRef.current?.style.height = `${heightRef.current?.offsetHeight}px`;
    } else {
      heightRef.current?.style.height = "96px";
    }
  }, [isOpen]);

  return (
    <div className="App" ref={heightRef} style={{height: 1100}}>
      <h1 onClick={collapsible}>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

Please accept the answer if it helps! Thank you!

It seems like you haven't defined the offsetHeight variable yet referencing it here

(heightRef.current!.style.height = '${offsetHeight}px')  

it's why typescript is yelling. Although we don't need to define this, instead grab the value by doing this heightRef.current.offsetHeight .

Also instead of assigning like this heightRef.current!.style.height = "96px" do this (heightRef.current?.style.height = "96px"). As far as I know, there is no such operator !. in javascript.

Related