145

I'd like to get the value after a hash in the URL of the current page and then be able to apply this in a new function... eg.

The URL could be

www.example.com/index.html#foo

And I would like to use this in conjunction with the following piece of code

$('ul#foo:first').show();

I'm kinda assuming/hoping there is some way of grabbing this, and turning it into a variable that I can then use in the second piece of code.

3
  • 10
    I don't have any code for you, but you should make sure to sanitize the input, as this seems ripe for code injection. Commented Nov 30, 2009 at 21:46
  • Understanding that this question is almost a decade old, 'ul#foo:first' doesn't make sense since IDs must be unique, therefore adding :first to the selector is redundant, unless you're duplicating IDs which is invalid. Note that even a decade ago, repeated IDs were still invalid. Commented Oct 3, 2018 at 17:37
  • Still was wrong a decade ago Commented Dec 9, 2018 at 2:32

7 Answers 7

298

Editor's note: the approach below has serious security implications and, depending upon the version of jQuery you are using, may expose your users to XSS attacks. For more detail, see the discussion of the possible attack in the comments on this answer or this explanation on Security Stack Exchange.

You can use the location.hash property to grab the hash of the current page:

var hash = window.location.hash;
$('ul'+hash+':first').show();

Note that this property already contains the # symbol at the beginning.

Actually you don't need the :first pseudo-selector since you are using the ID selector, is assumed that IDs are unique within the DOM.

In case you want to get the hash from an URL string, you can use the String.substring method:

var url = "http://example.com/file.htm#foo";
var hash = url.substring(url.indexOf('#')); // '#foo'

Advice: Be aware that the user can change the hash as he wants, injecting anything to your selector, you should check the hash before using it.

Sign up to request clarification or add additional context in comments.

11 Comments

Note that jQuery selectors can be used to execute custom javascript code, so using unsanitized hashes is horribly, horribly insecure. There is a half-assed fix for this in recent jQuery versions for selectors which contain a # before the injected code, but you are still at risk if you remove the # mark from the beginning of location.hash. E. g. var hash = location.hash.slice(1); $('ul.item'+hash).show().append($('#content')); this will execute a script tag put in the hash. It is a good habit to use $('body').find('ul'+hash+':first') instead of $('ul'+hash+':first').
Some browers return the hash symbol, and some don't, so it's safer to use: var hash = location.hash.replace('#', '');
Alice runs a web site, Bob visits it, authenticates and receives a session cookie. (Some time might pass here, Bob might even close his browser.) Charlie sends Bob a mail saying "check out this cool link!". Bob opens the link, which leads to a site controlled by Charlie. The page redirects Bob's browser to a page on Alice's site with an attack payload in the hash. The payload is executed, and since the browser still remembers the cookies, it can just send them to Charlie.
@Tgr, thank you for elaborating and connecting the dots. This concrete example makes me (and hopefully others) more inclined towards vigilance in keeping things secure.
@buffer: $(userInput) is generally unsafe because $ is overloaded and might either search for existing nodes or create new ones depending on whether the string contains <> characters. $(document).find(userInput) will always search for existing nodes so it is less unsafe. That said, the best practice is to always sanitize user input, e.g. if you use alphanumeric ids make sure it is alphanumeric.
|
37

location.hash is not safe for IE , in case of IE ( including IE9 ) , if your page contains iframe , then after manual refresh inside iframe content get location.hash value is old( value for first page load ). while manual retrieved value is different than location.hash so always retrieve it through document.URL

var hash = document.URL.substr(document.URL.indexOf('#')+1) 

1 Comment

Update: document.URL does not contain hash value on firefox 3.6 so location.href is safe var hash = location.href.substr(location.href.indexOf('#')+1)
6

For those who are looking for pure javascript solution

 document.getElementById(location.hash.substring(1)).style.display = 'block'

Hope this saves you some time.

Comments

5

Since jQuery 1.9, the :target selector will match the URL hash. So you could do:

$(":target").show(); // or $("ul:target").show();

Which would select the element with the ID matching the hash and show it.

2 Comments

is there a way to extract the hash as a string instead of match id?
@ina Do you mean get the hash from jQuery's :target as a string? If so I don't believe so.
3

I'm using this to address the security implications noted in @CMS's answer.

// example 1: www.example.com/index.html#foo

// load correct subpage from URL hash if it exists
$(window).on('load', function () {
    var hash = window.location.hash;
    if (hash) {
        hash = hash.replace('#',''); // strip the # at the beginning of the string
        hash = hash.replace(/([^a-z0-9]+)/gi, '-'); // strip all non-alphanumeric characters
        hash = '#' + hash; // hash now equals #foo with example 1

        // do stuff with hash
        $( 'ul' + hash + ':first' ).show();
        // etc...
    }
});

Comments

2

I would suggest better cek first if the current page has a hash. Otherwise it will be undefined.

$(window).on('load', function(){        
    if( location.hash && location.hash.length ) {
       var hash = decodeURIComponent(location.hash.substr(1));
       $('ul'+hash+':first').show();;
    }       
});

Comments

2

I found the marked answer wasn't sufficient for me. It states that getting the hash from the URL has huge security flaws but offers no real way of combatting it. There are ways out there of sanitizing the URL if you want to go that route, but if you're simply trying to show() a container, or apply some CSS/classes to the hash-matching ID container, then there's a much simpler way...

Introducing the :target selector.

The :target pseudo-class represents the unique element that has a matching id to the URL's fragment, meaning you can apply JS to it by simply doing something like:

$(':target').show();

Or in my case, just un-hiding the element I want with CSS only:

:target {
    display: block;
}

I know the OP's answer is almost exactly 13 years old, but this is a significantly easier and more secure way of achieving the same effect without dealing with getting the URL, splitting it up, sanitizing it - and hell, you can even avoid JS altogether with this method.

And yes, the :target selector is well-supported

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.