ReferenceError: document is not defined (in plain JavaScript)
JavascriptJavascript Problem Overview
I get the a "ReferenceError: document is not defined" while trying to
var body = document.getElementsByTagName("body")[0];
I have seen this before in others code and didn't cause any trouble. Why is it now? The companied HTML page is just a div inside the body.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/quiz.css" />
<script type="text/javascript" src="js/quiz.js"></script>
</head>
<body>
<div id="divid">Next</div>
</body>
</html>
the code is the following:
(function(){
var body = document.getElementsByTagName("body")[0];
function Question(question, choices, correctAns) {
this.question = question;
this.choices = choices;
this.correctAns = correctAns;
}
Question.prototype.checkAns = function(givenAns){
if (this.correctAns === givenAns) {
console.log("OK");
}
};
function Quiz() {
this.questions = [];
}
Quiz.prototype.showAllQuestions = function(){
this.questions.forEach(function(questions){
console.log(questions.question);
});
};
Quiz.prototype.showQuiz = function(){
this.questions.forEach(function(questions){
for (var i=0; i < questions.choices.length; i+=1) {
body.innerHTML(
"<input type=\"radio\" name=\"sex\" value=\"male\">"
+ questions.choices[i] + "<br>");
}
});
};
var q1 = new Question("What is red?", ["Color","Animal","Building"],1);
var q2 = new Question("Most popular music?", ["Latin","Pop","Rock"],2);
var quiz = new Quiz();
quiz.questions.push(q1);
quiz.questions.push(q2);
quiz.showAllQuestions();
})();
Try the whole code in this link HERE
Javascript Solutions
Solution 1 - Javascript
This happened with me because I was using Next JS
which has server side rendering. When you are using server side rendering there is no browser. Hence, there will not be any variable window
or document
. Hence this error shows up.
Work around :
If you are using Next JS you can use the dynamic rendering to prevent server side rendering for the component.
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(() => import('../components/List'), {
ssr: false
})
export default () => <DynamicComponentWithNoSSR />
If you are using any other server side rendering library. Then add the code that you want to run at the client side in componentDidMount
. If you are using React Hooks then use useEffects
in the place of componentsDidMount
.
import React, {useState, useEffects} from 'react';
const DynamicComponentWithNoSSR = <>Some JSX</>
export default function App(){
[a,setA] = useState();
useEffect(() => {
setA(<DynamicComponentWithNoSSR/>)
});
return (<>{a}<>)
}
References :
Solution 2 - Javascript
It depends on when the self executing anonymous function is running. It is possible that it is running before window.document
is defined.
In that case, try adding a listener
window.addEventListener('load', yourFunction, false);
// ..... or
window.addEventListener('DOMContentLoaded', yourFunction, false);
yourFunction () {
// some ocde
}
Update: (after the update of the question and inclusion of the code)
Read the following about the issues in referencing DOM elements from a JavaScript inserted and run in head
element:
Solution 3 - Javascript
Try adding the script element just before the /body tag like that
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/quiz.css" />
</head>
<body>
<div id="divid">Next</div>
<script type="text/javascript" src="js/quiz.js"></script>
</body>
</html>
Solution 4 - Javascript
You may deactivate ssr for the whole component (check Trect's answer), but it's overkill since you only need to skip one line in ssr.
You should only check if document
is defined (determining if the function is called server-side -no document- or client-side -document defined-):
if (typeof document === 'undefined') {
// during server evaluation
} else {
// during client's browser evaluation
}
In your case, you don't need to do anything server-side, you may do something like:
var body = null;
if (typeof document !== 'undefined') {
// will run in client's browser only
body = document.getElementsByTagName("body")[0];
}
Solution 5 - Javascript
Adding "defer" attribute to <script>
tag can also fix it.
<script defer src="yourScript.js"></script>
In this case you can keep <script>
inside of <head>
.
Solution 6 - Javascript
This issue happened when you call the eliment which didn't created yet
You called the body and it's component in <head >
Call the file in the end of< body >
Just before </body>
will solve it.
Solution 7 - Javascript
If you want to access the HTML DOM Document Object directly in Typescript, this implies that you will use the browser as the environment and have the Type Script tooling generate the code behind, while you use a code editor like VsCode to debug through your typescript.
const document: Document = document as Document;
or if you want to use it into a class just do:
class ExampleClass {
private document: Document;
private btn: HTMLElement;
constructor() {
this.document = document as Document;
}
public exampleOfGettingAButton(): void {
this.btn = this.document.getElementById("my-btn");
}
}
Solution 8 - Javascript
Problem: I got this error while using tailwind components from [tailwind-elements]. (https://tailwind-elements.com/)
Explanation: The error is caused because NextJs renders the page in the server only and in the server document (document is used inside tailwind-elements)is not available.
Solution: Use a dynamic route from NextJS.
import dynamic from "next/dynamic";
const {} = dynamic(import("tw-elements"), { ssr: false });
Solution 9 - Javascript
try: window.document......
var body = window.document.getElementsByTagName("body")[0];