In usability we trust

UX and all things web

Google Maps API 3 – InfoWindows

Using InfoWindows is a brilliant way to display information about a certain location. Since they provides you with a space to put text or whatever HTML you please, they can be used in very interesting ways. In this article, which is the fourth in a series about Google Maps API 3, I will show you how to make good use of this great feature.

The InfoWindow object

The InfoWindow object will open an InfoWindow somewhere on a map. It looks like a speech bubble and the tip of its stem typically points to a certain object on the map. Often it’s pointing at a marker, but it doesn’t have to be. It can point at any other object or any coordinate on the map.

The object resides in the google.map.InfoWindow namespace and takes an optional argument which is options. Options is an object literal in which you can define all the properties for the InfoWindow. This means that you can create an empty InfoWindow object for later use, but most of the time you’ll probably want to fill it with some sort of content right away. To fill it with content you’ll need to use the property content. It can be set either on creation of the object or afterwards using the setContent() method. It can be either a text string, a string containing HTML, or a reference to an existing HTML node.

Setting the scene

We will start with a map with one marker on it. If you don’t know how to create a map and add markers to it, I suggest that you read the previous articles in this series first.

For those of you that are already familiar with the concepts, here’s the code for creating a map and adding a marker to it:

// Creating an option object for the map
var options = {  
	zoom: 7,
	center: new google.maps.LatLng(56.83, 15.16),
	mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Initializing the map
var map = new google.maps.Map(document.getElementById('map'), options); 
// Creating a marker
var marker = new google.maps.Marker({
  position: new google.maps.LatLng(56.8848, 14.7730), 
  map: map,
  title: 'My workplace'
});

This will result in a map that looks like this:

Adding an InfoWindow

Now that we have the scene set, lets add an InfoWindow to it. In this example we will instantly fill the InfoWindow with some content, in this case the classic text string “Hello world”:

// Creating an InfoWindow object
var infowindow = new google.maps.InfoWindow({
  content: 'Hello world'
});

Showing the InfoWindow

We have now created an InfoWindow object but not yet added it to the map. To make it appear we have to first open it and that’s done with its method open(). This method takes two arguments: the map object which it will be added to and optionally an anchor where it will point to. The anchor must be an object on the map that exposes a position property. As of now this will probably be a marker.

If you don’t pass on the second argument you must provide the InfoWindow object with a position. This is done with either the attribute position in options or via its setPosition() method. In this example however, we will pass our marker as the second argument so that the InfoWindow will point straight at it.

infowindow.open(map, marker);

Now the InfoWindow will be visible on the map and will look like this:

Note that the default behavior of the map is that it pans so that all of the InfoWindow is visible. This behavior can be overridden by setting the property disableAutoPan to false.

Adding a click event

As of now our InfoWindow is automatically opened when our map loads. Most of the time we want it to open when something is clicked and that’s exactly the functionality we’re going to add next. We’re going to add a click event to the marker so that when it’s being clicked the InfoWindow will open.

To add an event to the marker we will need to use the addListener() method found in google.maps.event. This method takes 3 arguments, the first one being the object it will be attached to, in this case the marker. The second argument defines what kind of event we want to add, in this case a click event. The third argument is a function which will be called when the event is being triggered. In this case we will use an anonymous function and we will move the code that opens the InfoWindow inside it.

Doing that the code will look like this:

google.maps.event.addListener(marker, 'click', function() {
  infowindow.open(map, marker);
});

Now, when we load our page the InfoWindow will not be visible until we click the marker. Then it will pop up.

Using multiple InfoWindows

You may have noticed that we create the InfoWindow outside the click event of the marker. Perhaps you’re thinking that we might as well could have put all of the code regarding the InfoWindow inside it. But there’s a good reason for not doing that. By creating the InfoWindow outside the event handler, we ensure that there only exists one InfoWindow at a time. If we had put the code for creating the InfoWindow inside the event handler we would have created a new InfoWindow each time the marker was clicked. Leaving us with several identical InfoWindows on top of each other.

Now there are ways to deal with this. We could for example check if the InfoWindow existed before creating it, but by creating it only once we completely avoid the problem all together.

If you’ve been programming in version 2 of the Google Maps API you’ll notice a significant difference here. In the old API we could only have one InfoWindow at a time, but now we can have several. Because of this we have to change how we think about them. There might be occasions when we want to display several of them at once, but often we will only want to display them one at a time.

More control over the Info Window

There are some other properties that you can add to options for added control of the InfoWindow. I’ve already mentioned content which defines what will be displayed inside of it and position which in lack of an anchor defines the position of the InfoWindow. But here’s all of the properties available for controlling the look and behavior of the InfoWindow:

content

This property defines the content of the InfoWindow. It can be either plain text, HTML or a reference to an existing HTML element. The InfoWindow will automatically adjust its size to fit the content.

disableAutoPan [boolean]

If set to true the map is no longer automatically panned to fit the InfoWindow. Default value is false.

maxWidth [number]

Sets the maximum width of the InfoWindow in pixels. It must be set before the InfoWindow is opened.

Another way of controlling the size of the InfoWindow is to add HTML with certain dimensions to it. This way you can control its size from you CSS.

pixelOffset [size]

If position is used to place the InfoWindow, pixelOffset defines how far away from this point the window should be positioned.

position [LatLng]

Defines the position the InfoWindow should be pointing at. If an anchor (the second argument of the open() method is set, it will override this property.

zIndex [number]

When displaying multiple InfoWindows at the same time, this property will determine the stack order of those.

Live demo

Check out the Live Demo showing the example used in this article.

Hopefully this article has provided you with a basic understanding of how to use InfoWindows in your maps but there are a lot more that can be done with them. They still lack a lot of the functionality found in the old API, like displaying a detail map inside it or having tabbed content. Some of these features will probably never find its way into the new API but fortunately it’s quite easy to build this functionality yourself. Keep your eyes open for my upcoming book where I will explain how to do some of this stuff.

Further reading

For more information about the InfoWindow object, check out the Official Google Maps Reference. You might also want to check out the section in the documentation about Overlays.

My Google Maps book

If you found this article useful you might be interested in my book Beginning Google Maps API 3. It covers everything you need to know to create awesome maps on your web sites. Buy it on Amazon.com

86 Comments

  1. I’m trying to loop through an array of infoWindows and add an event listener to each of them. However, you can’t pass

  2. good tutorial

    could u plz tell us a littlebit about how to customize the infowindow?

  3. I appreciate the initiative from google to enable us customise maps. However i have a problem i want to solve inside the info windows i have created.

    I have added a couple of links in each info window. But now i need to maximise each info window when a user clicks on each link after which they may minimize and return to summary info window or close.

  4. Hello, thanks a lot for your articles, they have helped me a lot.

    I am currently working on my university thesis which uses Google Maps API v3 and I have a problem with the info windows.

    I am using a php loop creating a marker for each child in an xml file with info about the Greek Universities:

    Placemark as $institution) {
    $uni_name = htmlspecialchars($institution->name);
    $uni_latlong = htmlspecialchars($institution->Point->coordinates);
    ?>
    var marker = new google.maps.Marker({
    position: new google.maps.LatLng(),
    map: map,
    title: ”,
    clickable: true
    });
    var infowindow = new google.maps.InfoWindow({
    content: ‘Hello world’
    });

    google.maps.event.addListener(marker, ‘click’, function() {
    infowindow.open(map, marker);
    });

    As it is, the info window appears only if you click the last marker the loop created. Of course this is due to using the same name for the marker variable on every cycle. How do you suggest I solve this? I am VERY confused. 😛

    Thanks in advanced,
    Teo

  5. Teo: Like you said yourself, just give each marker and infowindow variable a unique name (marker1, marker2, etc) and it will work for you.

    Glad to hear that my articles have helped you! That is always nice to hear! :-)

  6. I will make an array :)

    Have the pride of knowing that not only you are AWESOME but you are helping me get my degree 😛

    I will send you the full code once I’m done for the lulz :)

  7. Ok, one more question and I’m covered (I hope). I made all the different infowindows appear, how can I close the others when I click and open a new one?

    Tried closeInfoWindow(); in the listener function but it disables all of them… :(

    • Teo: The easiest way to do this is to just have one instance of the InfoWindow object that you reuse over and over again. That way when you click a new marker the infoWindow is “moved” from where it’s currently at, to point at the new marker.

      Use its setContent method to load it with the correct content.

  8. Hi Gabriel,

    Thanks A LOT for this article, understanding how the new InfoWindow works is very helpful, and makes great sense.

    I just thought I’d ask, do you know if the tabbed InfoWindows from V2 will be implemented anytime soon? Or perhaps is it implemented but just not yet documented?

    Cheers!

  9. John: As far as I know tabbed InfoWindows is not implemented in v3. Whether or not it’s going to be implemented I don’t know.

  10. Hello,

    I like the way that V3 is implemented in JS, but I have problem to change the layout of InfoWindow, because it has no longer the second parameter (ID) like in V2
    marker.openExtInfoWindow(map, ElementID,…).
    And now I can not make any CSS to change the layout of InfoWindow.
    When I search the code I found that the top tag of InfoWindow is so max. what I can do is define some style for this class and child tags, but there is no diffenrence between the top left and top right corner divs (no id or class).
    Any suggestions how to solve this problem or should I better return to V2 coding?

  11. Is it possible to have a infowindow connected to a polygon?

  12. Dick: That’s is entirely possible.

  13. Does V3 support tabbed InfoWindow? I use openInfoWindowTabsHtml in V2. I hope V3 has the similar feature.

  14. Hwy man, I am trying to do the thing you said but I cannot :( Could you make the following comments code that would work?

    function markerselect(id) {

    map.panTo(markers[id].position);

    // if tempinfowindow exists close it or whatever
    // if it does not exist make it have the contents of infowindows[id]

    tempinfowindow.open(map, markers[id]);
    }

    Thanks in advanced :)

  15. Hello again,

    I tried to link an information window to a polygon in the same manner as for a marker, but failed. Can you see here http://liftstol.se/test.htm what I’m doing wrong?

    Thank you in advance!

    // Dick

  16. Does API V3 will let us to use tabbed infowindows ? I really need this !

  17. Does the v3 InfoWindow not have some sort of ‘onClose event’? I’m aware of the ‘closeclick’ event but I want to trigger a function whenever the infowindow is closed by any means (clicking the x or programatically).

  18. Dad00: No there’s currently no tabbed InfoWindows in API 3. There are however different ways of implementing 3d party tabs in an InfoWindow. Check out this discussion in the Google Maps JavaScript API v3 group.

    Jason: There’s no onClose event to my knowledge. I think you are right there are definitely cases where an onClose event would be called for.

    • sir pls tell me how i can decode uri component from fusion table to my javascript code. it give error like malfunction decodeURIComponent function..
      and also tell me how i can get more than 500 rows of data from fusion table to the Query

  19. Can we call Javascript from inside (the content) of an infowindow?

  20. Hi Gabriel,
    I am new to Java and I am trying to run this map with infowindow going away after you click another. If I am creating infowindow new every time its works but only keeping all the windows. my issue seems to be ‘infowindow.setcontent(itext);’
    please help me out, I am sure it is just a little thing.
    Thank you.
    Alfred

    var infowindow;
    function initialize() {
    var myOptions = {
    zoom: 6,
    center: new google.maps.LatLng(-42.945397, 171.565676),
    mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    var map = new google.maps.Map(document.getElementById(“map_canvas”),
    myOptions);

    setMarkers(map, days);
    infowindow = new google.maps.InfoWindow({ content: “blabla”});

    }

    var days = [
    [‘Day 1: Kaikoura’, -42.416667, 173.683333,1,’ Click here for Wikipedia‘],
    [‘Day 2-4: Nelson Lake’, -41.819167, 172.8375, 2,’ Click here for Wikipedia‘],
    [‘Day 5: Paparoa ‘,-42.083333, 171.5, 3,’ Click here for Wikipedia‘],
    [‘Day 6: Okatiro ‘,-43.2, 170.216667, 4,’ Click here for Wikipedia‘],
    [‘Day 7: Franz Josef Glacier’, -43.466997, 170.191528, 5,’ Click here for Wikipedia‘],
    [‘Day 8-9: Queenstown ‘,-45.031111, 168.6625, 6,’ Click here for Wikipedia‘],
    [‘Day 10: Hollyford Track ‘,-44.7350590018039,168.208030237917 , 7,’ Click here for Wikipedia‘],
    [‘Day 11: Milford Sound ‘,-44.675, 167.929444 , 8,’ Click here for Wikipedia on Milford Sound‘],
    [‘Day 12: Lake Pukaki ‘,-44.116667, 170.166667, 9,’ Click here for Wikipedia on Lake Pukaki‘],
    [‘Day 13: Mt Cook National Park ‘,-43.733333, 170.1 , 10,’ Click here for Wikipedia on Mount Cook National Park‘],
    [‘Day 14: Christchurch ‘,-43.53, 172.620278 , 11,’ Click here for Wikipedia‘]
    ];

    function setMarkers(map, locations) {
    // Add markers to the map

    for (var i = 0; i < locations.length; i++) {
    var beach = locations[i];
    var myLatLng = new google.maps.LatLng(beach[1], beach[2]);
    var marker = new google.maps.Marker({
    position: myLatLng,
    map: map,
    title: beach[0],
    zIndex: beach[3]
    });
    attachSecretMessage(map,marker,beach[4]);
    }

    };
    function attachSecretMessage(map,marker,itext) {
    // var infowindow = new google.maps.InfoWindow(
    // { content: itext});
    google.maps.event.addListener(marker, 'click', function() {
    infowindow.setcontent(itext);
    // infowindow.setPosition(marker);
    infowindow.open(map,marker);

    });
    };
    //function attachSecretMessage(map,marker,itext) {
    // var infowindow = new google.maps.InfoWindow(
    // { content: itext
    // });
    // google.maps.event.addListener(marker, 'click', function() {
    // infowindow.open(map,marker);
    // });
    //};

  21. hello; ok we can see infowindows when we clicked the marker and we can add text for example “hello world”. my question is how can i add photo or image into infowindow. this mean when i click the marker infowindow is opening and i can see the photo which i add it before i see alot of site like this. please help me to add photo to infowindows
    thnx a lot..!

  22. I think I speak for most people, that one of the richest features of the bespoke development of GoogleMaps API was TABS.

    Pamela’s version is functional, but visually non appealing with a lot of lost space.

    Personally… I’ll be sticking with v2 (reluctantly).

  23. Martel: It’s really easy to add photos since you can add any html you like instead of the text hello world. Just add an <img> as the value for the content property like this:


    var infowindow = new google.maps.InfoWindow({
      content: '<img src="url/to/your/image/" alt="" />'
    });

    Todd: I agree with you that InfoWindow tabs is a very appealing feature in API v2. Start an uproar in the API forum, and maybe the API team will add it in v3! :-) You could also add a feature request. The API is still in Beta so everything is possible.

  24. Thank you for this tutorial. It was really helpful.

    I just want to share something.

    I created a markerArray variable to store the markers in the map. I also had the infoArray variable to store all the associated infowindow. (All these were done using PHP and mySql).

    I tried to loop through the action listener so as to reduce the code. But I encountered the same problem as stated above. The infowindow is displayed only for the last marker. But I found a solution to this problem. And that is by adding a function inside the loop itself.

    After adding all the markers from the database, I looped the markerArray and called the function addInfo with the parameters markerArray[x],infoArray[x],map.

    Inside this function I added the addListener. And to my surprise, it worked.

    Lastly, thanks for this tutorial. It was really helpful.

  25. Frederick Ricaforte

    June 8, 2010 at 2:28 am

    Infowindow doesn’t really look nice in a small map, basically the rounded corners and the balloon tip takes so much space. Is there a way to use the smaller square balloon in V3?

    Although there are available examples to replace the infowindow, but most of the solutions fixed size images which are not as flexible as the current infowindow.

    Hope you could share some of your tricks to solve this. Thanks!

  26. Maybe I am slow…..but I can’t seem to get the concept of what I need to add for multiple markers. Can someone provide a link with an example? Thank you very much!

  27. Hi,
    I’m not a JavaScript man but can recognise simple statements and repeat them to expand on existing code. Can you direct me to a sample where I can add multiple custom markers plus an info window for each marker. I have found all this individually but I’m not able to combine the features.
    I’ll be internally grateful after devoting 3 days on this…
    Cheers,
    Rene

  28. Frederick Ricaforte

    June 11, 2010 at 4:09 am

    @Rene: If you have not found an answer to your question, probably you can look into complex overlay example. Just play with the image and location a little then add some extra info with the location then you should have your multiple custom markers. Finally follow the example above to add in the infowindows. Hope this helps

  29. I encountered the same problem as others when using a for loop to create events for markers. Perhaps it is an issue with the API, but regardless, I remember from my Java days that funny things can happen when references to things are passed around and you don’t know what exactly is being done.

    But anyhow, I was speculating that with the unwanted behavior we are all getting the event thingy-ma-bobber must work as follows:

    1. You register the event
    2. Something somewhere stores that you registered an event to that item
    3. For the action that it takes upon click it stores a function pointer
    *4.* For the arguments to this function, it stores a pointer to the arguments.

    This means that when you put the function in a for loop as so:

    for(var i=0; i<arr.length;++i){
    google.maps.events.addListener(arr[i],'click', function(){
    ActionFunction(arr[i]);
    });
    }

    It must be the case that ActionFunction is still in the same scope, meaning that it still points to the same function with the same argument. This means that every time the for loop iterates, it gives it a pointer to the same function with the same arguments, and you only have the affect of changing what those arguments (which are just boxes that hold pointers) point to. Therefore, you get what was pointed to by those parameters on the last iteration. And thus, with the solution that Ricky came up with, it calls a regular function first, meaning that pointers to the parameters of this function are pushed on the stack on each iteration and the function is called. Each time the event is registered the last even registration is completely out of scope, and thus the API is not able to take whatever shortcut it did before.

    Note: This is just an attempt for me to rationalize the behavior of the API and is complete speculation on my part. I actually have no clue and am in fact not fully satisfied with this explanation as I feel that there is a whole in my logic somewhere…

    So, just curious, have you ever encountered an issue like this when using the V3 API? For those of you who used the version two API's, has anyone encountered this issue? I am just wondering if this is the intended behavior, because it seems so unintuitive…

  30. Hi,

    This is a great tutorial! I was able to implement getting multiple markers on my map, but I’m having problems with the InfoWindow passing the correct text to the correct marker. It basically picks the last text that gets presented, and passes it to any marker that is clicked. Javascript is not my forte, and I have it running as echo statements in PHP. Can somebody take a look at this code and help me figure out how to make this work so that each marker gets the correct text? Thanks!

    while($row = mysql_fetch_array($result))
    {
    echo “var marker = new google.maps.Marker({n”;
    echo ” position : new google.maps.LatLng(” . $row[‘latitude’] . “,” . $row[‘longitude’] . “),n”;
    echo ” map : map,n”;
    echo ” icon : ‘images/photo.png’n”;
    echo “});n”;
    echo “var infowindow = new google.maps.InfoWindow({n”;
    echo ” content : ‘” . addslashes($row[‘description’]) . “‘n”;
    echo “})n”;
    echo “google.maps.event.addListener(marker, ‘click’, function() {n”;
    echo ” infowindow.open(map, marker);n”;
    echo “})n”;
    }

    This code gives the following results :

    var marker = new google.maps.Marker({
    position : new google.maps.LatLng(32.396989,-111.004427),
    map : map,
    icon : ‘images/photo.png’
    });
    var infowindow = new google.maps.InfoWindow({
    content : ‘Hill located in West Lambert Lane Park. Great 360 views of Tucson and the surrounding area.’
    })
    google.maps.event.addListener(marker, ‘click’, function() {
    infowindow.open(map, marker);
    })
    var marker = new google.maps.Marker({
    position : new google.maps.LatLng(32.420879,-110.982298),
    map : map,
    icon : ‘images/photo.png’
    });
    var infowindow = new google.maps.InfoWindow({
    content : ‘Another hillside location in Oro Valley. Great views to the west for storms in the valley.’
    })
    google.maps.event.addListener(marker, ‘click’, function() {
    infowindow.open(map, marker);
    })

    Which is good, but only the last content text gets passed to any marker I click on. Thanks for the look!

    Mark

  31. Hi there,
    I have generated a map with a bunch of markers and ifnoboxes that contain text/addresses etc that are visible. What I am struggling with is the format to add photographs. I have added a field in the phpmysql database (mediumblob) but am unsure wether I provide the url for the picture or what to do next…I am a bit of a noob at this so any help would be great.
    Many thanks
    Sean

  32. I have a map with mutiple markers and info windows and found your tutorial instrumental in getting this working. I have a sidebar with a list of the places identified and would now like to be able to link to the information window.

    My javascript is very basic, how can I do this?

    My map is http://www.planetengineering.com.au/maptest/index.html

    Bronwyn

  33. Hi Gabriel,

    anyway a great tutorial, well done.

    Can you please clarify how manage a lot of infowindows so that a behaviour is the same as it is in version 2 ?
    If I use another variable for each marker (infowindow and content) then I can see another content for each marker but with click on another infowindows the previous one is still open.

    If I use one varible of marker, infowindow and content for each marker than the window’s closing work well but I can see only one content.

  34. @mirekh
    I think you’re close. You can have multiple variable of marker but you must declare a global infowindow variable. But the the trick is to put the declaration of the infowindow inside a function like this:

    ////////////////////////
    var iw; // Global InfoWindow
    var map; // Global Map

    function initialize() {
    // map declarations here
    iw = new google.maps.InfoWindow();
    // for loop
    var mymarker = new google.maps.Marker({position:myLatLng,map:map});
    createMyInfoWindow(mymarker,"my content");
    // end of for loop
    }

    function createMyInfoWindow(mymarker,mycontent) {
    google.maps.event.addListener(mymarker, 'click', function(){iw.setContent(mycontent);iw.open(map, mymarker);});
    }
    ////////////////////////

    This is similar to what @Alfred Laggner posted above, although simpler.
    Hope this helps!

  35. Hello,

    I couldn’t get the multiple markers, multiple info windows to work, no matter what was said above.

    When in a loop:

    for (var i = 0; i < markers.length; i++) {
    var marker = markers[i];
    var infowindow = new google.maps.InfoWindow({
    content: "holding..."
    });

    google.maps.event.addListener(marker, 'click', function () {
    infowindow.open(map, maker);
    });
    }

    This always showed the last marker that was bound to map so the info window always appeared on the last marker. Bit of a problem really.

    After reading http://bit.ly/aEtHk1 it showed me the mistake everyone here has made and the actual solution!


    for (var i = 0; i < markers.length; i++) {
    var marker = markers[i];
    var infowindow = new google.maps.InfoWindow({
    content: "holding..."
    });

    google.maps.event.addListener(marker, 'click', function () {
    infowindow.setContent(this.html);
    infowindow.open(map, this);
    });
    }

    Changes in bold. As you have all seen the event fires for each marker, but as you were calling infowindow.open(map, marker) javascript engine’s memory location thingymabob (not good with names) held the last reference to marker. But you had passed in the marker to the event, so by calling this in place of marker, you get what you are looking for.

    Hope this helps someone out.

    Colin

  36. Hello,

    I am able to display content on Info Window by creating InfoWindow object, however i am unable to get default link(e.g. Directions, Search nearby, Saveto & More link).

    I am unable to find any method of InfoWindow object by using that i can show the above utility link in InfoWindow.

    Thanks,
    Rajeev Jha

  37. The code given by Colin Wiseman worked for me.
    Thanks!

  38. @Colin Wiseman
    “html” must be setted in markes:
    After, ‘content: “holding…”‘, add ‘html: “content”‘
    for (var i = 0; i < markers.length; i++) {
    var marker = markers[i];
    var infowindow = new google.maps.InfoWindow({
    content: "holding…",
    html: "content"
    });

  39. This is a great tutorial.
    For anyone who is a javascript newb (like me) who wants to do more than one infowindow remember to rename infowindow, and marker in all the places they appear (except on the google document parts)

    // Creating a marker first marker
    var marker = new google.maps.Marker(
    {
    position: new google.maps.LatLng(-41.21250, 174.89934),
    map: map,
    title: ‘My workplace’
    });

    //Info window
    var infowindow = new google.maps.InfoWindow({
    content: ‘Suck my balls’
    });

    //open info window when the map loads
    //infowindow.open(map, marker);

    //only open info window when marker is clicked
    google.maps.event.addListener(marker, ‘click’, function()
    {
    infowindow.open(map, marker);
    });

    //************** second marker
    // Creating a marker
    var marker2 = new google.maps.Marker(
    {
    position: new google.maps.LatLng(-41.22531, 174.90583),
    map: map,
    title: ‘Spider’
    });

    //Info window
    var infowindow2 = new google.maps.InfoWindow({
    content: ‘South Park Rules’
    });

    //open info window when the map loads
    //infowindow2.open(map, marker2);

    //only open info window when marker is clicked
    google.maps.event.addListener(marker2, ‘click’, function()
    {
    infowindow2.open(map, marker2);
    });
    }

  40. Hi Gabriel,

    Firstly, a great book, easy to follow, enjoyed every chapter ! Now to my problem regarding infoWindows, followed your tutorial on page 90 to create a function closure to ensure each infoWindow has its own respective content but to no avail, all my infoWindows display the same content, clone of the last infoWindow. The only thing I did different from your tutorial was that I was geocoding addresses to get the position for the marker. In my case, I am not provided with latlng upfront, hence I have to geocode the addresses to derive the latlng for the markers. Appreciate if you could shed some light, thks. My code looks something like this:

    function setMarkers(map, appointments, jobHasAppointment)
    {
    for(var i=0;i<jobAppointments.length;i++)
    {
    // use object literal instead ….
    var riskAddress = jobAppointments[i].split('^')[0];
    var comments = jobAppointments[i].split('$')[1];
    var jobID = jobAppointments[1].split('$')[0];

    geocoder.geocode({ 'address': riskAddress }, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
    map.setCenter(results[0].geometry.location);

    if (jobHasAppointment == jobHasAppointments.Yes) {
    var appointmentMarkerImage = new google.maps.MarkerImage(pushPinURL + j++ + ".png")
    var marker = new google.maps.Marker({
    icon: appointmentMarkerImage,
    map: map,
    title: 'job#: ' + jobID,
    position: results[0].geometry.location
    });
    points.push(results[0].geometry.location);
    }
    else {
    var marker = new google.maps.Marker({
    map: map,
    title: 'job#: ' + jobID,
    position: results[0].geometry.location
    });
    }

    (function(jobID, comments,marker) {
    google.maps.event.addListener(marker, 'click', function() {
    var jobID = new google.maps.InfoWindow;
    var content = '’+Comment+”;
    infowindow.setContent(content);
    infowindow.open(map, marker);
    });
    })(jobID, comments, marker);
    } else {
    alert(“Geocode was not successful for the following reason: ” + status);
    }
    });
    }
    }
    }

  41. the event is closeclick
    google.maps.event.addListener(infowindow,’closeclick’, function() {
    map.panTo(infowindow.getPosition());
    });

  42. Can some body help be in this info window related question http://stackoverflow.com/feeds/question/3921823

    I need to have info window content just like that in maps.goole.com with address and controls like ‘Directions’, ‘Near by’ etc.
    Is it possible?

  43. I tried to fill an Infowindow with a second map(detailmap/minimap) of a marker-position. Until now I failed in V3.
    Is it possible at all in V3? (in V2 it was possible).
    If possible, can you publish an example?

    The only way I succeed until now, was creating an minimap outside the infowindow in another div, like the overview example of google.

    thanks for your attention.

  44. this is my code.can somebody please tell why the map doesnt get displayed on my page??i’ve read the posts but i cant find the problem.thank you.

    function initialize() {
    var myLatlng = new google.maps.LatLng(38.306219,21.785905);
    var myOptions = {
    zoom: 4,
    center: myLatlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    var map = new google.maps.Map(document.getElementById(“map_canvas”), myOptions);

    var contentString = ”+
    ”+
    ”+
    ‘blabla’+
    ”+
    ‘blabla ‘ +
    ”+
    ”;

    var infowindow = new google.maps.InfoWindow({
    content: contentString
    });

    var marker = new google.maps.Marker({
    position: myLatlng,
    map: map,
    title: ‘Bla’
    });
    google.maps.event.addListener(marker, ‘click’, function() {
    infowindow.open(map,marker);
    });
    }

  45. …continue…

  46. Answer to Yiannis (Your question why the map doesnt get displayed on my page??)

    I found only a misinterpretation of quotes in your code:

    complete working document:
    (I changed every ‘lower than’ in || to have no conflicts in this comment
    copy code, change them back and run in your browser)
    ||!DOCTYPE html>
    ||html>
    ||head>
    ||meta http-equiv=”content-type” content=”text/html; charset=UTF-8″/>
    ||title>Google Maps JavaScript API v3 Example: Info Window Simple
    ||style>
    #map_canvas{width:512px; height:512px;
    position: relative;
    }
    ||/style>
    ||script type=”text/javascript” src=”http://maps.google.com/maps/api/js?sensor=false”>
    ||/script>
    ||script type=”text/javascript”>
    function initialize() {
    var myLatlng = new google.maps.LatLng(38.306219,21.785905);
    var myOptions = {
    zoom: 4,
    center: myLatlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById(“map_canvas”), myOptions);
    var contentString = ‘ ‘+’ ‘+’ ‘+’blabla’+’ ‘+’blabla ‘ +’ ‘+’ ‘;
    var infowindow = new google.maps.InfoWindow({
    content: contentString
    });
    var marker = new google.maps.Marker({
    position: myLatlng,
    map: map,
    title: ‘Bla’
    });
    google.maps.event.addListener(marker, ‘click’, function() {
    infowindow.open(map,marker);
    });
    }
    ||/script>
    ||/head>
    ||body onload=”initialize()”>
    ||table>
    ||tr>
    ||td>
    ||div id=”map_canvas” style=”width:500px;height:400px;”>
    ||/div>
    ||/td>
    ||td> You can see the map now
    ||/td>
    ||/table>
    ||/body>
    ||/html>

    A bit to late maybe, but I hope it helps somebody.

  47. Hi!

    Thanks for a great article series on the Google map api! Have you tried this?

    http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/examples.html

    Would be great to see an article about infoboxes in use.

    Keep up the great writing!

  48. Mats: Hi! No I haven’t tried that out but it looks interesting. Another interesting utility library is InfoBubble.

    Good article idea! I might just take you up on that. Thanks!

  49. It’s Hell infoWindow close..

    I can’t close that..!!

    What can I do

  50. Joseph Han: Try: infoWindow.close();

  51. Hello,
    thank you for your tutorial.
    i follow it, but i have a little problem and i’m trying to find the solution:
    Now my page open automatically the infowindow, but When a user clicks the close button the infoWindow closes. I want the
    user to be able to click on the marker to reopen the infoWindow and now is not possible.
    thank you in advance, and please help me as well as possible cause i don’t know HTML, JAVA etc but i know COBOL CICS IMS!!!!

    this is the page http://www.unforgettablerome.it/prova3.html

    Tom

  52. Finally, I have long sought a solution to this problem for your site. You have provided lots of great scripts for Google maps, did everything as described and all rabotet, if anyone is having problems please contact me I will help you.

  53. This is an awesome tutorial but how can I change the infowindow typeface?

    thanks,
    Jon

  54. Hello,
    I’ve read your excellent book on Google Maps API3, and I try to reproduce one of the examples of Chap 7 about creating a detailed map.
    I just added the input of an address (through jQuery autocomplete) and the geocoding of that address to get a pair of coordinates.
    So the map has 1 marker. Now, the problem: if I click the marker, the Infowindow opens with the correct content. If I close the infowindow and re-click the marker it does not open anymore !! And I have no idea about how it’s like that ???
    If I changed the address, I’m not any more able to open the infowindow ??
    So the infowindow opens only once in my page !! Please help…
    Below, the code of the page:

    Test AutoComplete

    body { font-family: Tahoma, Verdana, Arial, sans-serif; font-size: 12px; color: #333333; }
    .addr { float: left; margin-bottom: 6px; }
    .canvas_style { margin-bottom: 4px; width: 500px; height: 400px; }
    .detail_style { width: 180px; height: 180px; }

    var map,geocoder,marker;

    function initialize(){
    var latlng = new google.maps.LatLng(50.465328,4.8676649);
    var options = { zoom: 14, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true };
    map = new google.maps.Map(document.getElementById(“map_canvas”), options);
    geocoder = new google.maps.Geocoder();
    marker = new google.maps.Marker({ map: map, clickable: true });
    }

    $(document).ready( function(){
    initialize();
    $(“#address”).css( { width: “300px” } );
    $(“#address”).focus();
    $(“#reset”).click(function() {
    $(“#address”).val(“”);
    $(“#address”).focus();
    initialize();
    });

    $(function(){
    $(“#address”).autocomplete({
    source: function(request, response){
    geocoder.geocode(
    { ‘address': request.term },
    function(results, status) {
    response( $.map( results, function(item) {
    return {
    label: item.formatted_address,
    value: item.formatted_address,
    latitude: item.geometry.location.lat(),
    longitude: item.geometry.location.lng()
    }
    }));
    })
    },
    select: function(event, ui) {
    var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
    marker.setPosition(location);
    marker.setTitle(‘Click me’);
    map.setZoom(16);
    map.setCenter(location);
    // Wrapping the event listener inside an anonymous function
    (function(map, marker) {
    // Creating the event listener. It now has access to the value of marker
    google.maps.event.addListener(marker, ‘click’, function() {
    $(“#map_detail”).appendTo(“#map_canvas”);
    var overviewOpts = { zoom: 18, center: marker.getPosition(), mapTypeId: google.maps.MapTypeId.SATELLITE, disableDefaultUI: true };
    var detailMap = new google.maps.Map( document.getElementById(“map_detail”), overviewOpts );
    var detailMarker = new google.maps.Marker({ position: marker.getPosition(), map: detailMap, clickable: false });
    var infowindow = new google.maps.InfoWindow({ position: marker.getPosition(), content: document.getElementById(“map_detail”) });
    infowindow.open(map, marker);
    });
    })(map, marker);
    }
    });
    });
    });

    Address:

  55. Hello, I am doing a project on Google maps API V3 and I have some problems. Could anyone help me? I have this code:

    var map;
    var placesArr = []; // Pinakas gia places (markers)
    var squaresArr = []; // pinakas gia squares (polugons)
    var roadsArr = []; // pinakas gia grammes (polylines)
    var infoWindow;
    function initialize() // Kaleitai otan emfanizetai o xarths
    {
    var drama = new google.maps.LatLng(41.150557,24.146292);
    map = new google.maps.Map(document.getElementById(“map”),
    {
    zoom: 16,
    center: drama,
    mapTypeId: google.maps.MapTypeId.ROADMAP

    });
    downloadUrl(“coordsDrama.xml”,readAndDisplayXML);

    }

    // Ektos apo emfanish KAI apo8hkeush markers/polygons/polylines stous pinakes placesArr, squaresArr, roadsArr
    function readAndDisplayXML(data) // orismos readAndDisplayXML ektos ths downloadUrl
    {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName(“marker”);
    for (var i = 0; i 0
    for (var i = 0; i < polys.length; i++) // Gia ka8e polygon i …
    {
    var points = polys[i].getElementsByTagName("point"); // …diabase ta points tou i polygon
    var info =polys[i].getAttribute("polygon info");
    var gpolyCoords = new Array(points.length) // ston pinaka gpolyCoords
    for (var j =0; j 0
    for (var i = 0; i < polyl.length; i++) // Gia ka8e polyline i …
    {
    var points = polyl[i].getElementsByTagName("point"); // …diabase ta points tou i polygon
    var gpolyCoords = new Array(points.length) // ston pinaka gpolyCoords
    for (var j =0; j < points.length; j++) // me auto to for
    gpolyCoords[j] = new google.maps.LatLng(parseFloat(points[j].getAttribute("lat")),parseFloat(points[j].getAttribute("lng")));

    // Emfanish sto xarth tou polugwnou apo ta shmeia tou gpolyCoords
    polyline = new google.maps.Polyline( // Oxi polugon
    {
    path: gpolyCoords, // ?uto eleipe
    strokeWeight: 3,
    fillColor: '#3B00FF',
    strokeColor: '#FF0000',
    geodesic: true
    });
    polyline.setMap(map); // Auth h entolh emfanizei to polyline panw ston xarth
    }
    roadsArr.push(polyl);
    }

    function downloadUrl(url,callback)
    {
    var request = window.ActiveXObject ?
    new ActiveXObject('Microsoft.XMLHTTP') :
    new XMLHttpRequest;

    request.onreadystatechange = function() {
    if (request.readyState == 4) {
    request.onreadystatechange = doNothing;
    callback(request, request.status);
    }
    };

    request.open('GET', url, true);
    request.send(null);
    }
    function doNothing() {}

    function doOnClick(id)
    {
    var state = document.getElementById(id).checked; // true ? false
    if (state == true) // Dior8: if (state == true)
    {
    if (id=="places") // Dior8: if (id=="places")
    {
    for (var i=0; i< placesArr.length; i++)

    placesArr[i].setMap(map);

    }
    else if (id=="squares")
    {
    for (var i=0; i< squaresArr.length; i++)

    squaresArr[i].setMap(map);// Kwdikas for gia squaresArr
    }
    else if (id=="roads")
    {
    for (var i=0; i< roadsArr.length; i++)

    roadsArr[i].setMap(map);// kwdikas for gia roadsArr
    }

    }
    else // to state tou epipedou (places/squares/roads) einai false
    { if (id=="roads") polyl.setMap(null);
    if (id=="squares") poly.setMap(null);

    // Kwdikas gia e3afanish tou epipedou, dhl. setMap(null);
    }

    }

    Places
    Squares
    Roads

    I load data from an xml file which is this

    When I click on the marker, I want to appear an infowindow with the info from the xml file.
    Also, there are 3 checkboxes. I want, for example when places are checked the markes are visible, when the squares is checked, the polygons are visible. Could please anybody hel me???

    Thanks in advance,
    Sophie

  56. Hello,

    This is very useful in me, as a new learner in Google Map API. This tutorial is clear enough to me and now will go further to next level.

    Thank you for sharing this knowledge.

    regards,
    sulle

  57. Just to let you know that I got a hyper link to your posting from search engine result advertisement top dog Themelis Cuiper :) – you are doing a cool job as he provides a hyperlink to you!

  58. hello,
    i have a problem when i use google map for my website,in my page i want the infowindow is outside of the map when infowindow width > the map container width,not in the map and overflow is hidder or the map pad to fit the infowindow.
    can you help me?

  59. I am trying to get a blank infowindow not attached to a marker to open on the map. (Eventually I want to populate this with geographic information based on the location of the click, but for starters I just want to get the infowindow to open). I have not had any success. Here is my code:

    (function() {

    window.onload = function() {

    var options = {
    zoom: 10,
    center: new google.maps.LatLng(42.5, -74),
    mapTypeId: google.maps.MapTypeId.SATELLITE
    };
    var map = new google.maps.Map(document.getElementById(‘map’), options);

    var infowindow = new google.maps.InfoWindow({
    content: ‘Hello world’
    });

    google.maps.event.addListener(map, ‘click’, function() {
    infowindow.open(map);
    });

    };

    })();

    Any suggestions? Thanks

    Frank B., New York

    • There’s one thing missing in your code, the position of the InfoWindow. If you want it to be at the center of the map you could do it like this:

      google.maps.event.addListener(map, 'click', function(e) {
      infowindow.setPosition(map.getCenter());
      infowindow.open(map);
      });

      • I am searching a long time now for a solution of my problem. I have a mysql database and want to show some stops of valencia in my map using php and js. I already could show my stops as markers in my map but no matter what i try i cant show for each stop a infowindow. I dont know much of js…. it would be so great if someone could help me with my problem!!!

        This is the code:

        echo ‘//<![CDATA[';//MAKE JS with PHP
        echo '
        var map; // Global Map
        function initialize() {
        var myLatlng = new google.maps.LatLng(39.466202, -0.381633);
        var myOptions = {
        zoom: 9,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.TERRAIN
        };
        map = new google.maps.Map(document.getElementById("map_valencia"), myOptions);
        ';/*end of JS snippet*/
        echo '
        var point = new Array();
        var text = new Array();
        ';/*end of JS snippet*/
        for ($r=0; $r<$rows; $r++){
        echo '
        point['.$r.'] = new google.maps.LatLng('.$x[$r].','.$y[$r].');
        text['.$r.'] = "'.$n[$r].'";
        ';/*end of JS snippet*/
        }
        echo '
        var infowindow = null;
        var marker = new Array();
        var image = "grafics/stp.png";
        for (i=0; i ‘;

      • I am searching a long time now for a solution of my problem. I have a mysql database and want to show some stops of valencia in my map using php and js. I already could show my stops as markers in my map but no matter what i try i cant show for each stop a infowindow. I dont know much of js…. it would be so great if someone could help me with my problem!!!

        This is the code:

        echo ‘//<![CDATA[';//MAKE JS with PHP
        echo '
        var map; // Global Map
        function initialize() {
        var myLatlng = new google.maps.LatLng(39.466202, -0.381633);
        var myOptions = {
        zoom: 9,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.TERRAIN
        };
        map = new google.maps.Map(document.getElementById("map_valencia"), myOptions);
        ';/*end of JS snippet*/
        echo '
        var point = new Array();
        var text = new Array();
        ';/*end of JS snippet*/
        for ($r=0; $r<$rows; $r++){
        echo '
        point['.$r.'] = new google.maps.LatLng('.$x[$r].','.$y[$r].');
        text['.$r.'] = "'.$n[$r].'";
        ';/*end of JS snippet*/
        }
        echo '
        var infowindow = null;
        var marker = new Array();
        var image = "grafics/stp.png";
        for (i=0; i ‘;

  60. Hey Gabriel

    Is it possible to load several markers to google maps at once from a text file? And if so how?

  61. Hi,

    This example, allows you to format your infowindow in CSS

    http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobubble/examples/example.html

    And allows you to make tabs.

    but I don’t know how to get the result CSS

    Anyone knows?

    thanks
    Sebastian

    • I am searching a long time now for a solution of my problem. I have a mysql database and want to show some stops of valencia in my map using php and js. I already could show my stops as markers in my map but no matter what i try i cant show for each stop a infowindow. I dont know much of js…. it would be so great if someone could help me with my problem!!!

      This is the code:

      echo ‘//<![CDATA[';//MAKE JS with PHP
      echo '
      var map; // Global Map
      function initialize() {
      var myLatlng = new google.maps.LatLng(39.466202, -0.381633);
      var myOptions = {
      zoom: 9,
      center: myLatlng,
      mapTypeId: google.maps.MapTypeId.TERRAIN
      };
      map = new google.maps.Map(document.getElementById("map_valencia"), myOptions);
      ';/*end of JS snippet*/
      echo '
      var point = new Array();
      var text = new Array();
      ';/*end of JS snippet*/
      for ($r=0; $r<$rows; $r++){
      echo '
      point['.$r.'] = new google.maps.LatLng('.$x[$r].','.$y[$r].');
      text['.$r.'] = "'.$n[$r].'";
      ';/*end of JS snippet*/
      }
      echo '
      var infowindow = null;
      var marker = new Array();
      var image = "grafics/stp.png";
      for (i=0; i ‘;

  62. instead of coord such as lat and long is possible to do with city,country,address????

  63. Thanks for telling me how to add multiple markers (NOT!!)

  64. I am playing with the infoWindow and in one of my sites, the “tip” of the infowindow and the “shadow” that occurs are distorted. Any idea what might cause such a thing? I’m thinking css, but have no idea what to look for besides things that affect the .infowindow class.

    • Yeah, it has probably something to do with the CSS. I’ve had similar problems when using Google Maps within other Frameworks. Look for CSS rules that affects all images, and then make sure you clear those out within the map div.

  65. Any example how to show multiple infowindows ? I also want to know how can we add another window on clicking some link on infowindow.

  66. Rodrigo Galhardo

    June 13, 2012 at 8:32 pm

    Please, Help Me..

    I’m trying to get the value of a variable that is formatted address, made by reverse geocode, and I’m trying to put it in InfoWindow, along with other information, but it does not appear, she does not like Sting takes the value that corresponds to address formatted, and must display the InfoWindow, what is my mistake? Can you help me?

    jaascript, see my code below:

    var infowindow;
    var map;
    var geocoder;

    function parseXml(str) {
    if (window.ActiveXObject) {
    var doc = new ActiveXObject(‘Microsoft.XMLDOM’);
    doc.loadXML(str);
    return doc;
    } else if (window.DOMParser) {
    return (new DOMParser).parseFromString(str, ‘text/xml’);
    }
    }

    function geocode(latlng) {
    var Rasc = “”;
    geocoder.geocode({‘latLng': latlng}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
    if (results[0]) {
    Rasc = results[0].formatted_address;
    //alert(Rasc);
    }
    }
    return Rasc;
    });
    }

    function initialize() {

    geocoder = new google.maps.Geocoder();
    var myLatlng = new google.maps.LatLng(-23.4419, -46.1419);
    var myOptions = {
    zoom: 16,
    panControl: true,
    noClear: true,
    center: myLatlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP

    }
    map = new google.maps.Map(document.getElementById(“map_canvas”), myOptions);

    // Conecta a uma pagina Xml e extrai as informaçoes de Lat e Long

    downloadUrl(“XML_busca_dados.aspx”, function (data) {
    var XMLPos = parseXml(data);

    var markers = XMLPos.documentElement.getElementsByTagName(“marker”);

    var latitude = “”;
    var longitude = “”;
    //var Rasc = “”;

    for (var i = 0; i < markers.length; i++) {
    latitude = markers[i].getAttribute("lat");
    longitude = markers[i].getAttribute("lng");

    var latlng = new google.maps.LatLng(parseFloat(markers[i].getAttribute("lat")),
    parseFloat(markers[i].getAttribute("lng")));

    var marker = createMarker('Nome:' + markers[i].getAttribute("apelido")
    + 'ID / IMEI: ‘ + markers[i].getAttribute(“name”)
    + ‘Data e Hora: ‘ + markers[i].getAttribute(“data”)
    + ‘Status GPS: ‘ + markers[i].getAttribute(“stagps”)
    + ‘Velocidade: ‘ + markers[i].getAttribute(“velocidade”) + ‘  KM/h’
    + ‘Latitude:’ + markers[i].getAttribute(“lat”)
    + ‘Longitude:’ + markers[i].getAttribute(“lng”)
    + ‘Localização:’ + geocode(latlng), latlng);

    }

    var pontoCentral = new google.maps.LatLng(parseFloat(latitude), parseFloat(longitude));
    map.panTo(pontoCentral);
    });
    }

    function createMarker(name, latlng) {
    var marker = new google.maps.Marker({ position: latlng, map: map, animation: google.maps.Animation.DROP});
    google.maps.event.addListener(marker, “click”, function () {
    if (infowindow) infowindow.close();
    infowindow = new google.maps.InfoWindow({ content: name });
    infowindow.open(map, marker);
    });
    return marker;
    }

    function drop() { for (var i = 0; i < markerArray.length; i++) { setTimeout(function () { addMarkerMethod(); }, i * 200); } }

  67. nice tuts, thanks u , i found this tuts

  68. Veronica DEL CARMEN HERNANDEZ

    October 2, 2012 at 9:27 pm

    hi help:

    I try to look at it on the map when you click on any part of the map which is set in a circle while you put your information such as latitude, longitude and radiusbut only managed to position the circle just to give you help pordias click me leave my mail pru.you @ gmail.com

  69. infowindow.open(map, marker); is not fitting the whole infowindow. But when I click the marker the map autopans to fit the whole infowindow. Why is the map not autopanning to fit the whole infowindow? I want the infowindow to show up automatically but it looks bad with the top of it cut off.

  70. Can i change the default style of infoWindow css . . ?? Becaude i want to remove extra white space displaying from style of window i.e width: 247px by default.

  71. How can you add multiple Infowindows for multiple polylines, this book didn’t cover this topic I am very frustrated…

  72. Can you put an image in the popup box? and what is the code for doing this??

  73. I can open infowindows from an link external to the Google map.

    I am trying to do the same using a select box to determine which infobox I open. Do you have any examples using an selectbox.

    This works
    Open Augusta Info Window
    Open Modoc Info Window
    This does not work.

    SELECT GAGE OF INTEREST
    Augusta
    Modoc

    Any suggestions?

  74. THANK you!

  75. infowindow continuously blinking every time page load??what’s the solution?

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>