Building a Web Browser with React and Electron
Web browsers are essential tools for navigating the web. While there are many great web browsers available, what if you could create your custom browser tailored to your specific needs and preferences? With electron-vite, we can do just that.
Electron-vite aims to provide a faster and leaner development experience for Electron. It combines the capabilities of Electron, a framework for building cross-platform desktop applications, with the simplicity and speed of Vite, a front-end build tool.
Using electron-vite, we will create a minimalist web browser in under an hour.
Get Started
To get started, you must have Node.js and npm installed on your system. Once you have Node.js and npm installed, you can create a new Electron-Vite project by running the following command in your terminal:
npm create @quick-start/electron@latest
// Follow the prompts to choose a project name, framework, and additional options. The following are the options I selected.
? Project name: prospect
? Select a framework: react
? Add TypeScript? Yes
? Add Electron updater plugin? No
? Enable Electron download mirror proxy? No
Select a UI Framework
After scaffolding your project with Electron and React, you should choose a UI Library to minimize the amount of work required to design the browser's interface. I picked Bootstrap and used the Cerulean theme from Bootswatch. You can use React Bootstrap, but I am faster at prototyping with vanilla Bootstrap.
Requirements
Before beginning this endeavor, let's have a clear set of requirements that we can use to ensure the proper functionality of our web browser.
As a user of the web browser, I should be able to:
Customize Electron Window
Electron gives you complete control over the appearance and behavior of your application's window. I can customize my browser's window size, position, title bar, and more.
I removed the window frame from my web browser to maximize it's minimalism. Check out src/main/index.tx and modify it to suit your needs (See GitHub Project).
You'll have to ensure that the webviewTag is set to true to ensure that webviews are supported in the application. This is required to display web pages.
const mainWindow = new BrowserWindow({
width: 900,
height: 670,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
webviewTag: true
},
frame: false
})
Create Components
The next step is to create the essential components for your browser, including an address bar and a splash screen.
AddressBar.tsx
This component will ensure users can browse the web and drag the browser window around their desktop.
import './styles.css'
const AddressBar = ({
url,
setUrl
}: {
url: string
setUrl: React.Dispatch<React.SetStateAction<string>>
}): JSX.Element => {
return (
<nav className="navbar bg-primary text-white p-2 border-bottom-dark sticky-top" id="drag">
<div className="container">
<input
type="text"
className="form-control border-primary shadow-sm"
id="no-drag"
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
</div>
</nav>
)
}
export default AddressBar
I assigned the nav element an ID of drag ensure the user can drag the window around without a title bar and the input element an ID of no-drag to ensure the user can activate the field. Next, I created a styles.css to assign the correct -webkit-app-region style.
领英推荐
#drag {
-webkit-app-region: drag;
}
#no-drag {
-webkit-app-region: no-drag;
}
For additional details, See the Electron Docs.
Splash.tsx
This will be visible when the user has an empty URL. This will ensure the user has a pleasant experience
import ProspectIcon from '../assets/prospect.png'
const Splash = (): JSX.Element => {
return (
<div className="p-5" id="drag">
<img src={ProspectIcon} alt="" style={{ maxWidth: 250 }} />
<h1>Prospect</h1>
<p>0.0.1</p>
</div>
)
}
export default Splash
Setup App.tsx
Now that we've created the essential components for our web browser, we need to tie it all together in App.tsx
import { useRef, useState } from 'react'
import AddressBar from './components/AddressBar'
import Splash from './components/Splash'
function App(): JSX.Element {
const [url, setUrl] = useState<string>('')
const webviewRef = useRef<HTMLWebViewElement>(null)
return (
<>
<AddressBar setUrl={setUrl} url={url} />
{url ? (
<webview
ref={webviewRef}
src={`${url.includes('https://') ? '' : 'https://'}${url}`}
></webview>
) : (
<Splash />
)}
</>
)
}
export default App
Run the Application
To get the application running, run the following command.
npm run dev
This will open the browser window in development.
As you can see, there is an issue with the way our browser is rendering the webpage. This is because no styling for the webview tag was included. To resolve this issue, I created a custom hook that we can use to measure the window dimensions, calculate the height required for the webview, and prevent any overflows from occurring by considering the height of the address bar.
useWindowDimensions
import { useEffect, useState } from 'react'
type WindowDimensions = {
width: number
height: number
}
const getWindowDimensions = (): WindowDimensions => {
const { innerWidth: width, innerHeight: height } = window
return {
width,
height
}
}
const useWindowsDimensions = (): WindowDimensions => {
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions())
useEffect(() => {
const handleResize = (): void => {
setWindowDimensions(getWindowDimensions())
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
return windowDimensions
}
export default useWindowsDimensions
With this custom hook in place, let's update App.tsx to use it and resolve this ugly issue.
import { useRef, useState } from 'react'
import './assets/styles.css'
import AddressBar from './components/AddressBar'
import useWindowsDimensions from './hooks/useWindowsDimensions'
import Splash from './components/Splash'
function App(): JSX.Element {
const [url, setUrl] = useState<string>('')
const windowDimensions = useWindowsDimensions()
const webviewRef = useRef<HTMLWebViewElement>(null)
return (
<>
<AddressBar setUrl={setUrl} url={url} />
{url ? (
<webview
ref={webviewRef}
src={`${url.includes('https://') ? '' : 'https://'}${url}`}
style={{
// height of address bar is 54 pixels
height: windowDimensions.height - 54
}}
></webview>
) : (
<Splash />
)}
</>
)
}
export default App
The Result
After following the instructions above, you've created your own web browser!
Want to check out Prospect, the browser built here? Check out the GitHub Repo.
Graphic Designer | Visual Designer | Learning Designer | Storyline & Rise Developer | Instructional Design | eLearning Developer | edTech | Multidisciplinary Professional
4 天前Wow! Your tutorial is really clear and direct, and there's something I particularly liked: you tested the app and showed that something was missing to correct the webpage rendering. After that, you explained how to implement the solution. The way you organized the article aligns with how I like to think, too! I'll be following your content from now on. ??
Graphic Designer | Visual Designer | Learning Designer | Storyline & Rise Developer | Instructional Design | eLearning Developer | edTech | Multidisciplinary Professional
4 天前Hey, Miguel R.! Do you know any group (Telegram or Linkedin) where people share knowledge about React and Electron? I just start to learn React and I'm in love for it. As a self-taught learning, I started a project and I'm having some issues with the react build feature (this doesn't working. It builds, but doesn't load the app). A group where we can share these kind of things will be helpful to me. Thanks!
The ROI Guy ? I help DEI Consultants get more warm leads ? Download my ROI of DEI white paper to learn the framework (see featured section)
8 个月Speed in development leads to quicker feedback loops, enhancing agility and efficiency in building innovative solutions. P.S.?Insightful post