Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I open a url from <a> on default OS browser? #1344

Closed
luicaps opened this issue Apr 1, 2015 · 21 comments

Comments

@luicaps
Copy link

commented Apr 1, 2015

I want to take an to an external website, but I do not want it to happen inside atom-shell, I want it to be in the default browser. How can I do that?

Thanks!

@maxogden

This comment has been minimized.

Copy link
Contributor

commented Apr 2, 2015

@zcbenz zcbenz closed this Apr 2, 2015

@AlicanC

This comment has been minimized.

Copy link

commented Sep 7, 2015

On my setup, I tried both shell.openExternal('http://example.com') and shell.openItem('http://example.com') and both opened the website in the background.

I ended up using child_process.execSync('start http://example.com') on Win32 and child_process.execSync('open http://example.com') on Darwin so the browser actually pops up and gets focus.

@suchipi

This comment has been minimized.

Copy link

commented Oct 21, 2015

On Linux, you can use xdg-open:
child_process.execSync('xdg-open http://example.com')

@AlicanC

This comment has been minimized.

Copy link

commented Oct 21, 2015

I have actually decided to use node-open. You should give it a try if you don't want to mess with escaping and such.

@havenchyk

This comment has been minimized.

Copy link

commented Jan 4, 2016

Guys, but your solutions are great, but I'm wondering how to intercept attempt to open url like "http://someurl.com" and then open in with shell.openExternal? Service worker allows to catch only requests to the files on the same domain. Is there ability to do this? /cc @maxogden @AlicanC

@rubencodes

This comment has been minimized.

Copy link

commented Jan 14, 2016

Same question here as @havenchyk, is there a way to tell electron to open links external by default?

@suchipi

This comment has been minimized.

Copy link

commented Jan 14, 2016

If your app only uses one window, and you can guarantee that every external link in your app opens in a new window (via eg. target="_blank"), you can do something like:

webContents.on('new-window', function(event, url){
  event.preventDefault();
  open(url);
});

Where webContents is your main BrowserWindow's webContents and open is a function that opens the url in your browser (I use node-open as recommended by AlicanC).

It'd be nice if there was an event fired when any link is clicked, so the app could decide if it should open in the browser, but I haven't found such an event if it exists.

@rubencodes

This comment has been minimized.

Copy link

commented Jan 14, 2016

I found this code snippet on S.O.:

    var shell = require('electron').shell;
    //open links externally by default
    $(document).on('click', 'a[href^="http"]', function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

Dropped it in my main index file, it seems to be working as far as I can tell, even for dynamically generated links. I'm too noob at electron to know if there are any drawbacks to this I should watch out for. Thoughts?

@pravdomil

This comment has been minimized.

Copy link
Contributor

commented Apr 12, 2016

I'm using this piece of code:

var handleRedirect = (e, url) => {
  if(url != webContents.getURL()) {
    e.preventDefault()
    require('electron').shell.openExternal(url)
  }
}

webContents.on('will-navigate', handleRedirect)
webContents.on('new-window', handleRedirect)
@peterlavey

This comment has been minimized.

Copy link

commented May 11, 2016

First declare a spawn proccess

`app.controller('GuideCtrl', ['$scope', ($scope)=>{
const spawn = require('child_process').spawn;

  $scope.openBrowser=(url)=>{
     let exec = spawn('explore', [url], {});
     exec.stdout.on('data', (data)=> {
        console.log('stdout: ' + data)
     });
  }

}])`

and before call the method

<a ng-click="openBrowser('https://google.com')">Goto google</a>

@greggman

This comment has been minimized.

Copy link
Contributor

commented Nov 23, 2016

Does shell.openExternal have any security issues? For example if links come off the net then raw net data is being passed to shell.openExternal or any of the other functions above. Does shell.openExternal make sure nothing bad's going to happen? Do I need to filter for schemas?

@stevenaubertin

This comment has been minimized.

Copy link

commented Dec 3, 2016

Base on the code from @rubencodes , i used :

   const shell = require('electron').shell;
   $('.open-in-browser').click((event) => {
           event.preventDefault();
           shell.openExternal(event.target.href);
   });

Then you just have to drop the 'open-in-browser' class to each elements you want to open in the browser.

@alangrainger

This comment has been minimized.

Copy link

commented Oct 26, 2017

Here's one that doesn't require JQuery, in case anyone else is hunting for it. It will automatically open any link that starts with 'http' in the external browser.

Put this in your renderer process:

// Open all links in external browser
let shell = require('electron').shell
document.addEventListener('click', function (event) {
  if (event.target.tagName === 'A' && event.target.href.startsWith('http')) {
    event.preventDefault()
    shell.openExternal(event.target.href)
  }
})
@MrDrProfX

This comment has been minimized.

Copy link

commented Jan 22, 2018

If you want ALL <a> tags to open in the default browser, try this in your main.ts:

const shell = require('electron').shell;

mainWin.webContents.on('will-navigate', (event, url) => {
  event.preventDefault()
  shell.openExternal(url)
});

This assumes your have a single page app like me. If not, you'll need to do some extra sanitizing.

@greggman

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2018

I just want to reiterate that using this with user content without a whitelist is probably a gaping security hole. I don't know what all various schemes do and what their inputs are but just as a simple example a link like this

 <a href="imessage:hello">click me</a>

Will prompt the user in Chrome and Safari on macOS but with the code above Electron will just open the app.

It almost feels like Electron itself should default to being more secure here rather than leave it to every individual programmer to figure out how to make it secure on their own.

At a minimum you probably want something like

function isSafeishURL(url) {
  return url.startsWith('http:') || url.startsWith('https:');
}

mainWin.webContents.on('will-navigate', (event, url) => {
  event.preventDefault();
  if (isSafeishURL(url)) {
    shell.openExternal(url);
  }
});
@MarshallOfSound

This comment has been minimized.

Copy link
Member

commented Jan 22, 2018

@greggman See the open external permission type in https://electronjs.org/docs/api/session#sessetpermissionrequesthandlerhandler

You can block those 👍

@tangliming

This comment has been minimized.

Copy link

commented May 15, 2018

Hi, I am using vue.js and solve this problem inspired by above discussion, in case some one like me using vue also have the same problem, I paste my code here.

<template>
<div class="board-item" v-for="element in list" :key="element.id">
<span><a class='board-item-a' :href='element.url' target='_blank'>{{element.title}}</a></span>
</div>
</template>

<script>
mounted () {
this.$el.querySelectorAll('.board-item-a').forEach(a => {
a.addEventListener('click', (e) => {
e.preventDefault()
require('electron').shell.openExternal(e.target.href)
})
})
},
</script>

@rsemscom

This comment has been minimized.

Copy link

commented May 29, 2018

Based on comment of @alangrainger - ts version:

const {app, shell, BrowserWindow} = require('electron');

...
mainWindow.webContents.on('new-window', function(event, url){
   event.preventDefault();
   shell.openExternal(url);
});
@GrantGryczan

This comment has been minimized.

Copy link

commented Jun 30, 2018

What about data URLs?

@steve-todorov

This comment has been minimized.

Copy link

commented Feb 17, 2019

Angular 7 version (with live reloads):

        const openExternalLinksInOSBrowser = (event, url) => {
            if (url.match(/.*localhost.*/gi) === null && (url.startsWith('http:') || url.startsWith('https:'))) {
                event.preventDefault();
                shell.openExternal(url);
            }
        };
        win.webContents.on('new-window', openExternalLinksInOSBrowser);
        win.webContents.on('will-navigate', openExternalLinksInOSBrowser);

The url.match(/.*localhost.*/gi) === null part is necessary because otherwise when you change something in your angular application it will open new window/tab in your OS browser instead of reloading it in the electron app.

@lefuturiste

This comment has been minimized.

Copy link

commented Jul 4, 2019

All the methods work fine but only on non root electron app, what can I use to open a external url on default OS browser on a root elevated process?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.