Skip to content

Add customizable homepage#2648

Open
Chickaboo wants to merge 8 commits intominbrowser:masterfrom
Chickaboo:homepage
Open

Add customizable homepage#2648
Chickaboo wants to merge 8 commits intominbrowser:masterfrom
Chickaboo:homepage

Conversation

@Chickaboo
Copy link
Contributor

Introduces a new customizable new tab page with clock, greeting, and search bar. Adds settings for enabling/disabling the homepage, choosing between default or custom URL, toggling clock and greeting, and selecting time format. Implements new internal protocols for 'min://newtab' and 'min://blank', updates localization, and refines related CSS and JS for the new tab and settings pages.
Screenshot 2025-10-19 213511
Screenshot 2025-10-19 213254
Screenshot 2025-10-19 213217
Screenshot 2025-10-19 213230

Introduces a new customizable new tab page with clock, greeting, and search bar. Adds settings for enabling/disabling the homepage, choosing between default or custom URL, toggling clock and greeting, and selecting time format. Implements new internal protocols for 'min://newtab' and 'min://blank', updates localization, and refines related CSS and JS for the new tab and settings pages.
Updated the new tab page to use the currently selected search engine instead of a hardcoded DuckDuckGo URL. Added the searchEngine utility script to index.html and modified performSearch to construct the search URL dynamically.
@PalmerAL
Copy link
Collaborator

PalmerAL commented Nov 9, 2025

Thanks for the PR!

I think it makes sense to have a setting to set a custom new tab URL. I'm less convinced that we should have a built-in page. My impression is that there are a lot of potential designs for a new tab page, and people tend to have strong opinions about which design is the best for them; designing something that makes most people happy would require a ton of different customization options and add a lot of complexity.

How would you feel about keeping just the setting to set a custom URL, and putting any specific page designs in an external repository?

Also, it would be good to figure out a better interaction between the NTP and the searchbar. When I open a new tab, I don't actually see the NTP, because the searchbar is covering it:

Screenshot 2025-11-09 at 2 04 40 PM

I think this should probably work like this (what do you think?):

  1. When you open a new tab, the searchbar is active and focused, but if a custom NTP is configured, no suggestions are shown underneath.
  2. The NTP is immediately visible.
  3. If you start typing in the searchbar, we start showing the searchbar suggestions and blur the NTP.

@PalmerAL
Copy link
Collaborator

PalmerAL commented Nov 9, 2025

Also, I should point out, we already have an option to set a custom image background on the new tab page:

Screenshot 2025-11-09 at 2 09 55 PM

We should ensure any changes are compatible with that.

@Chickaboo
Copy link
Contributor Author

That sounds good to me. I'll remove the new tab page and make it so that in the settings, you can choose either the NTP or a custom URL. A better implemetion of the NTP and the search bar interaction is something I will look into. I think the outline you gave will work well. I'll try to work on this sometime soon, but it might be a week or two.

1. Removed custom homepage
2. Moved new tab custom URL to Additional settings
3. Added the NTP Functionality to the preferences as well as maintaining it on the new tab widget
4. Improved new-tab design and visibility of NTP
This reverts commit 826ddae, reversing
changes made to 8021bfb.
This reverts commit 08bf957.
Removed legacy homepage and new tab page code, including blank and custom homepage files and settings. Added new settings for new tab page: blank, custom URL, or background image, with UI and logic updates throughout the app. Updated CSS and JS to support new background image and custom URL options, and removed unused homepage-related code and translations.
@Chickaboo
Copy link
Contributor Author

Everything should be done. I moved the Custom URL into the Additional Settings. There is now a dropdown menu which has three options one for Blank, Custom URL, and NTP. I made sure that both the NTP widget and the preferences functionality are in sync. The changes to the new tab design have been made as well. I think the outline you gave worked great. Let me know if there are any changes or tweaks needed—its looking pretty good to me though. 9b59089

Copy link
Collaborator

@PalmerAL PalmerAL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good! I left some comments on the code, but I think the functionality is working well.

@@ -43,14 +43,28 @@ function addTab (tabId = tabs.add(), options = {}) {
destroyTab(tabs.getSelected())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be a case added to this if statement to destroy the current tab if it equals the NTP URL. Currently, if I close all my tabs, I get a single tab with the NTP; then if I create a new private tab, I get two tabs: one with the NTP, and a second with the private tab. I'd expect that the NTP would close when I create the new tab.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the desired functionality is already achieved for the New Tab Picture. Are you asking for this behavior to be applied for the custom URL as well?

2026-01-04.20-04-10.mp4

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying; I'll get on it!


// if the tab is a new, blank tab, replace it with the custom new tab page
let isCustomUrl = false
if (!tabs.get(tabId).url && !tabs.get(tabId).private) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be possible for a site to create a popup with no URL (I'm not sure exactly), in which case we shouldn't show the NTP. Perhaps we could solve that by also checking enterEditMode here, and only showing the NTP if it's true.

// if the tab is a new, blank tab, replace it with the custom new tab page
let isCustomUrl = false
if (!tabs.get(tabId).url && !tabs.get(tabId).private) {
const newTabUrl = settings.get('newTabUrl')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this setting isn't a URL, could we rename it to something like newTabType?

(newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl'))

if (isNTP) {
searchbar.el.classList.add('searchbar-hidden')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could just skip calling searchbar.showResults in this case (perhaps calling searchbar.hide instead if that's necessary), and then we no longer need the hidden class.

blobInstance: null,
reloadBackground: function () {
const newTabUrl = settings.get('newTabUrl')
if (newTabUrl === 'blank') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the setting has never been modified, settings.get will return undefined, which this also needs to check for (ie since a blank page is the default value, undefined and "blank" should be treated the same way)

"settingsNewTabUrlBlank": "Blank Page",
"settingsNewTabUrlCustomUrl": "Custom URL",
"settingsNewTabUrlBackgroundImage": "Background Image",
"settingsNewTabUrlUploadImage": "Upload Image",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to also add these as the title attributes of the camera and delete buttons on the new tab page.

sendIPCToWindow(window, 'zoomOut')
}
},
// Hidden item to enable shortcut on numpad
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like an accidental change, can you revert it?

Sets the default #ntp-background scale to 1.03 and removes the scale transform from the blurred state, ensuring a more consistent background appearance.
Copilot AI review requested due to automatic review settings January 5, 2026 02:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a customizable new tab page feature that allows users to choose between a blank page, a custom URL, or a background image for new tabs. The implementation includes new settings UI, background image upload/removal functionality, and visual enhancements with blur effects and searchbar transitions.

  • Adds new tab page customization with three modes: blank, custom URL, and background image
  • Implements settings interface with dropdown selection and custom URL input field
  • Integrates background image picker with automatic file handling and visual blur effects

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
pages/settings/settings.js Adds event handlers for new tab URL dropdown and custom URL input, including auto-prompt for background image selection
pages/settings/index.html Adds UI elements for new tab page settings with dropdown and text input field
main/menu.js Removes numpad zoom shortcuts (appears unrelated to the PR's main purpose)
localization/languages/en-US.json Adds localization strings for new tab page settings options
js/preload/default.js Adds IPC message handlers for uploading and removing new tab background images
js/newTabPage.js Refactors background handling to support multiple new tab modes and adds image picker/removal functions
js/navbar/tabEditor.js Implements searchbar hiding logic for new tab pages and blur effect when typing
js/browserUI.js Adds logic to set custom URL when creating new tabs and prevents entering edit mode for custom URLs
css/searchbar.css Adds transition and visibility classes for searchbar hiding animation
css/newTabPage.css Adds blur effect and scale transform for background images
Comments suppressed due to low confidence (1)

main/menu.js:276

  • The removal of the numpad zoom shortcuts appears unrelated to the PR's stated purpose of adding a customizable homepage. If this change is intentional, it should be in a separate PR or explained in the description. Otherwise, this may be an accidental deletion.
        {
          label: l('appMenuActualSize'),
          accelerator: 'CmdOrCtrl+0',
          click: function (item, window) {
            sendIPCToWindow(window, 'zoomReset')
          }
        },
        {
          type: 'separator'
        },
        {
          label: l('appMenuFocusMode'),
          accelerator: undefined,
          type: 'checkbox',
          checked: false,
          click: function (item, window) {
            if (isFocusMode) {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return
}

await fs.promises.copyFile(filePath[0], newTabPage.imagePath)
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for the file copy operation. If copying the file fails (e.g., due to permissions, disk space, or invalid file path), the error will be unhandled and may cause unexpected behavior. Consider wrapping this in a try-catch block and handling errors appropriately.

Suggested change
await fs.promises.copyFile(filePath[0], newTabPage.imagePath)
try {
await fs.promises.copyFile(filePath[0], newTabPage.imagePath)
} catch (err) {
console.error('Failed to copy new tab background image:', err)
return
}

Copilot uses AI. Check for mistakes.
newTabPage.reloadBackground()
},
removeImage: async function () {
await fs.promises.unlink(newTabPage.imagePath)
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for the file unlink operation. If removing the file fails (e.g., file doesn't exist, permissions issue), the error will be unhandled. Consider wrapping this in a try-catch block to handle errors gracefully.

Suggested change
await fs.promises.unlink(newTabPage.imagePath)
try {
await fs.promises.unlink(newTabPage.imagePath)
} catch (err) {
// Ignore if the file does not exist; log and abort for other errors.
if (err && err.code === 'ENOENT') {
// File is already gone; continue to update settings/UI.
} else {
console.error('Failed to remove new tab background image:', err)
return
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +56
(newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl'))

Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NTP (New Tab Page) detection logic is incomplete. It only checks for 'backgroundImage' and 'customUrl' modes, but doesn't account for the 'blank' mode. When newTabUrl is set to 'blank' and currentURL is empty, this should also be considered an NTP scenario. The current logic may show the searchbar when it should be hidden in blank mode.

Suggested change
(newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl'))
(newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl')) ||
(newTabUrlMode === 'blank' && currentURL === '')

Copilot uses AI. Check for mistakes.
Comment on lines +162 to +165
type="text"
id="new-tab-custom-url-input"
style="margin-left: 0.5em; min-width: 325px"
hidden
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom URL input field lacks input validation. Users can enter any text, including invalid URLs, which may cause issues when the browser tries to navigate to them. Consider adding validation to ensure the input is a valid URL, or at least provide user feedback when an invalid URL is entered.

Suggested change
type="text"
id="new-tab-custom-url-input"
style="margin-left: 0.5em; min-width: 325px"
hidden
type="url"
id="new-tab-custom-url-input"
style="margin-left: 0.5em; min-width: 325px"
hidden
placeholder="https://example.com"

Copilot uses AI. Check for mistakes.

newTabUrlDropdown.addEventListener('change', function () {
settings.set('newTabUrl', this.value)
newTabCustomUrlInput.hidden = true
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The statement newTabCustomUrlInput.hidden = true is unnecessary here. When the dropdown value changes, the code already handles the visibility of the custom URL input field in the subsequent conditional (lines 271-276). This line sets it to hidden unconditionally, only to potentially set it to false again immediately after, which is redundant.

Suggested change
newTabCustomUrlInput.hidden = true

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants