Tutorial: Connect to MetaMask using vanilla JavaScript
Lucas N. Munhoz
Posted on May 4, 2022
In this post, you’ll learn how simply connect your frontend application to a MetaMask Wallet using simple JavaScript code.
The intention is to demonstrate how simple it is without all the noise of libraries like React in the way.
Let’s get started.
Create a new Vanilla JavaScript Sandbox
First, we start by opening https://codesandbox.io/ and creating a new Sandbox for VanillaJS.
You can delete all the content within index.js
file, so we have a fresh start.
Now we are ready to go!
Understanding window.ethereum
In order to connect to the MetaMask wallet, we need to programmatically check to make sure that the user has the MetaMask extension installed in the browser. To do that, we can simply paste this code into our index.js
file:
if (typeof window.ethereum !== "undefined") {
console.log("MetaMask is installed!");
} else {
console.log("MetaMask is NOT installed!");
}
After pasting it, check the Console tab on your Sandbox, you should be able to the console.log
message. If you don’t have MetaMask installed, make your you do by visiting the official website and selecting the correct version for your browser.
Continuing, what is window.ethereum
anyway? Without going too much into detail, the browser extension injects this object into your browser. This ethereum
object is more formally called Ethereum Provider, which as the name says, provides you an API to access Ethereum-based networks.
If you are more curious about Ethereum Provider API, read more here.
Check if the user’s browser has access to the MetaMask wallet
Let’s now create a button that will tell us if we are ready to connect to MetaMask or not based if window.ethereum
is available or not.
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<button id="connect-btn">Connect Wallet</button>
<script src="src/index.js"></script>
</body>
</html>
// index.js
function isEthereumAvailable() {
return window.ethereum !== "undefined"
}
const connectButton = document.getElementById('connect-btn')
function init() {
if (isEthereumAvailable()) {
connectButton.textContent = 'Connect Wallet'
connectButton.removeAttribute('disabled')
} else {
connectButton.textContent = 'Ethereum not available. Please install MetaMask!'
connectButton.setAttribute('disabled', true)
}
}
init()
Great, now we have a button that will be disabled and tell the user to go and install MetaMask in the case is not available. Otherwise, it will display “Connect Wallet”.
Display the MetaMask popup to ask for permissions to view user accounts
Now that we have our button, we need to make sure when it’s clicked, it will popup MetaMask for the user.
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<button id="connect-btn">Connect Wallet</button>
<-- Add this line so we can display the connected account -->
<div id="account">Account not connected</div>
<-- Add this line so we can display errors -->
<div id="error"></div>
<script src="src/index.js"></script>
</body>
</html>
function isEthereumAvailable() {
return window.ethereum !== "undefined";
}
const connectButton = document.getElementById("connect-btn");
// + Add this two elements to give feedback to the user
const accountElement = document.getElementById("account");
const errorElement = document.getElementById("error");
// + Add this function to request the user accounts
// This will display the MetaMask popup to the user
async function getAccounts() {
return window.ethereum.request({
method: "eth_requestAccounts"
});
}
// + Add the connect function that will be triggered by the connectButton
function connect() {
connectButton.textContent = "Loading...";
errorElement.textContent = "";
return getAccounts().then(showAccount).catch(showError);
}
// + Display the selected wallet address
function showAccount(accounts) {
if (accounts.length > 0) {
accountElement.textContent = 'Account: ' + accounts[0];
connectButton.textContent = "Connected";
}
}
// + Displays an error to the user when trying to connect the wallet
function showError(err) {
connectButton.textContent = "Connect Wallet";
errorElement.textContent = err.message;
}
function init() {
if (isEthereumAvailable()) {
connectButton.textContent = "Connect Wallet";
connectButton.removeAttribute("disabled");
// + Add this line to add the connect function to the button
connectButton.addEventListener("click", connect);
} else {
connectButton.textContent = "Ethereum not available";
connectButton.setAttribute("disabled", true);
}
}
init();
Detect and display the current network
Let’s add a new element to our index.html
... same as before
<body>
<button id="connect-btn">Connect Wallet</button>
<div id="account">Account not connected</div>
<div id="error"></div>
<!-- Add this line so we can display the connected network -->
<div id="chain"></div>
<script src="src/index.js"></script>
</body>
In our index.js
file, we will add a couple of new functions:
... same as before
// Add this after errorElement variable
const chainElement = document.getElementById("chain");
async function getChainId() {
const chainId = await window.ethereum.request({ method: "eth_chainId" });
return chainId;
}
// We will use this to display a friendly name for the chain,
// as the getChainId method will give us the chainId.
function getChainName(chainId) {
switch (chainId) {
case "0x1":
return "Ethereum Main Network";
case "0x3":
return "Ropsten Test Network";
case "0x4":
return "Rinkeby Test Network";
case "0x5":
return "Goerli Test Network";
case "0x2a":
return "Kovan Test Network";
default:
default: "Chain not supported"
}
}
function showChain(chainId) {
chainElement.textContent = getChainName(chainId);
}
And in our connect
function, let’s update so it will look like this:
function connect() {
connectButton.textContent = "Loading...";
chainElement.textContent = "";
errorElement.textContent = "";
return getAccounts()
.then(showAccount)
.then(getChainId)
.then(showChain)
.catch(showError);
}
And there you have it, the final result should look like this:
Posted on May 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.