0

In html, I have a button element with no text. It has a child svg element with some paths and rectangles. It works fine:

I try to create this in javascript. The problem is, that the button is not visible. If I set some text to it with textContent or innerHtml, the button is visible with the text, but the svg is not there. How can I create this button in javascript? This is the code:

var myButton = document.createElement("button");
myButton.setAttribute("class", "my-button");
myButton.setAttribute("id", "foo");

var mySVG = document.createElement("svg");
mySVG.setAttribute("id", "my-svg");
mySVG.setAttribute("viewBox", "0 0 12.25 15.45");

var icon1 = document.createElement("g");
icon1.setAttribute("class", "g-element1");
icon1.setAttribute("id", "g1");

var iconPath = document.createElement("path");
iconPath.setAttribute("d", "M0,25L0,0l12.25,7.7L0,15.45z");

var icon2 = document.createElement("g");
icon2.setAttribute("class", "g-element2");
icon2.setAttribute("id", "g2");

var rect1 = document.createElement("rect");
rect1.setAttribute("x", "0");
rect1.setAttribute("y", "0");
rect1.setAttribute("width", "4.1");
rect1.setAttribute("height", "15.45");

var rect2 = document.createElement("rect");
rect2.setAttribute("x", "8.1");
rect2.setAttribute("y", "0");
rect2.setAttribute("width", "4.1");
rect2.setAttribute("height", "15.45");

icon1.appendChild(iconPath);
icon2.appendChild(rect1);
icon2.appendChild(rect2);

mySVG.appendChild(icon1);
mySVG.appendChild(icon2);

myButton.appendChild(mySVG);

document.getElementById('some-element').appendChild(myButton)
.my-button {
  font-size: 14px;
  height: 17px;
  cursor: pointer;
  margin-left: 5px;
  &:hover, &:focus {
    opacity: .8;
  }
}
<div id="some-element">
<button class="my-button" id="foo">
    <svg id="my-svg" viewBox="0 0 12.25 15.45">
        <g class="g-element1" id="g1">
            <path d="M0,25L0,0l12.25,7.7L0,15.45z"/>
        </g>
        <g class="g-element2" id="g2">
            <rect x="0" y="0" width="4.1" height="15.45"/>
            <rect x="8.1" y="0" width="4.1" height="15.45"/>
         </g>
     </svg>
 </button>
 </div>

Also when I create just the button in javascript and I set no text to it (and no svg either), the button is not visible.

T.Poe
  • 1,949
  • 6
  • 28
  • 59
  • Can you try adding a text node with a blank space? document.createTextNode("\u00A0"); – Xedret Jul 19 '18 at 19:13
  • 2
    As stated in [here](https://stackoverflow.com/questions/8215021/create-svg-tag-with-javascript) you could try `document.createElementNS("http://www.w3.org/2000/svg", "svg");` instead of `document.createElement("svg");` but that is just an idea – Henrique Pauli Jul 19 '18 at 19:16
  • 2
    I see two buttons when running the example code posted. Neither of them look to have any SVG in them, but I'm not sure what the SVG is supposed to display. Do note that you must use unique IDs in your HTML. – Heretic Monkey Jul 19 '18 at 19:22
  • @HenriquePauli That's actually almost correct, except I had to use this construct on all child elements of the svg and their attributes like [here](https://stackoverflow.com/questions/3492322/javascript-createelement-and-svg). Now it works. Thanks for the suggestion. – T.Poe Jul 19 '18 at 19:54

4 Answers4

1

The SVG appears to be collapsing to zero width and height inside the button. You can prevent this by setting an explicit width and height on it:

.my-button {
  font-size: 14px;
  height: 17px;
  cursor: pointer;
  margin-left: 5px;
  &:hover, &:focus {
    opacity: .8;
  }
}
#my-svg {width: 100%; height: 100%}
<div id="some-element">
<button class="my-button" id="foo">
    <svg id="my-svg" viewBox="0 0 12.25 15.45">
        <g class="g-element1" id="g1">
            <path d="M0,25L0,0l12.25,7.7L0,15.45z"/>
        </g>
        <g class="g-element2" id="g2">
            <rect x="0" y="0" width="4.1" height="15.45"/>
            <rect x="8.1" y="0" width="4.1" height="15.45"/>
         </g>
     </svg>
 </button>
 </div>

The same should apply whether the SVG is defined inline or script-generated. But note that when generating non-HTML nodes it's necessary to use .createElementNS() and include the namespace, as below:

var myButton = document.createElement("button");
myButton.setAttribute("class", "my-button");
myButton.setAttribute("id", "foo");

var svgns = "http://www.w3.org/2000/svg";

var mySVG = document.createElementNS(svgns, "svg");
mySVG.setAttribute("id", "my-svg");
mySVG.setAttribute("viewBox", "0 0 12.25 15.45");

var icon1 = document.createElementNS(svgns, "g");
icon1.setAttribute("class", "g-element1");
icon1.setAttribute("id", "g1");

var iconPath = document.createElementNS(svgns, "path");
iconPath.setAttribute("d", "M0,25L0,0l12.25,7.7L0,15.45z");

var icon2 = document.createElementNS(svgns, "g");
icon2.setAttribute("class", "g-element2");
icon2.setAttribute("id", "g2");

var rect1 = document.createElementNS(svgns, "rect");
rect1.setAttribute("x", "0");
rect1.setAttribute("y", "0");
rect1.setAttribute("width", "4.1");
rect1.setAttribute("height", "15.45");

var rect2 = document.createElementNS(svgns, "rect");
rect2.setAttribute("x", "8.1");
rect2.setAttribute("y", "0");
rect2.setAttribute("width", "4.1");
rect2.setAttribute("height", "15.45");

icon1.appendChild(iconPath);
icon2.appendChild(rect1);
icon2.appendChild(rect2);

mySVG.appendChild(icon1);
mySVG.appendChild(icon2);

document.getElementById('some-element').appendChild(mySVG)
#my-svg {
  width: 100%;
  height: 100%
}

button {height: 14px}
<button id="some-element"></div>
Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
1

When creating SVG elements (including elements inside the the SVG tage) using JavaScript, you need to use document.createElementNS(namespaceURI, qualifiedName) with the appropriate namespace URI http://www.w3.org/2000/svg. You also need to assign a height to the SVG element.

Because you have to use the namespace for every element that you're creating within the SVG tag as well as the SVG tag itself, you may want to curry the function to save space and prevent typos:

const createSVGElement = qn => document.createElementNS("http://www.w3.org/2000/svg", qn);

Here's your code fixed:

var myButton = document.createElement("button");
myButton.setAttribute("class", "my-button");
myButton.setAttribute("id", "foo");

const createSVGElement = qn => document.createElementNS("http://www.w3.org/2000/svg", qn);

var mySVG = createSVGElement("svg");
mySVG.setAttribute("id", "my-svg");
mySVG.setAttribute('height', "14px");
mySVG.setAttribute("viewBox", "0 0 12.25 15.45");

var icon1 = createSVGElement("g");
icon1.setAttribute("class", "g-element1");
icon1.setAttribute("id", "g1");

var iconPath = createSVGElement("path");
iconPath.setAttribute("d", "M0,25L0,0l12.25,7.7L0,15.45z");

var icon2 = createSVGElement("g");
icon2.setAttribute("class", "g-element2");
icon2.setAttribute("id", "g2");

var rect1 = createSVGElement("rect");
rect1.setAttribute("x", "0");
rect1.setAttribute("y", "0");
rect1.setAttribute("width", "4.1");
rect1.setAttribute("height", "15.45");

var rect2 = createSVGElement("rect");
rect2.setAttribute("x", "8.1");
rect2.setAttribute("y", "0");
rect2.setAttribute("width", "4.1");
rect2.setAttribute("height", "15.45");

icon1.appendChild(iconPath);
icon2.appendChild(rect1);
icon2.appendChild(rect2);

mySVG.appendChild(icon1);
mySVG.appendChild(icon2);

myButton.appendChild(mySVG);

document.getElementById("some-element").appendChild(myButton);
.my-button {
  font-size: 14px;
  height: 17px;
  cursor: pointer;
  margin-left: 5px;
  &:hover, &:focus {
    opacity: .8;
  }
}
<div id="some-element">
<button class="my-button" id="foo">
    <svg id="my-svg" viewBox="0 0 12.25 15.45" height="14px">
        <g class="g-element1" id="g1">
            <path d="M0,25L0,0l12.25,7.7L0,15.45z"/>
        </g>
        <g class="g-element2" id="g2">
            <rect x="0" y="0" width="4.1" height="15.45"/>
            <rect x="8.1" y="0" width="4.1" height="15.45"/>
         </g>
     </svg>
 </button>
 </div>
0

Setting the svg element as innerHTML to the button might give you the result.

document.getElementById('foo').innerHTML = '<svg id="my-svg" viewBox="0 0 12.25 15.45"><g class="g-element1" id="g1"><path d="M0,25L0,0l12.25,7.7L0,15.45z"/></g><g class="g-element2" id="g2"><rect x="0" y="0" width="4.1" height="15.45"/><rect x="8.1" y="0" width="4.1" height="15.45"/></g></svg>';
.my-button {
  font-size: 14px;
  height: 17px;
  cursor: pointer;
  margin-left: 5px;
  &:hover, &:focus {
    opacity: .8;
  }
}

svg
{
    height:100%;
  width:100%;
}
<div id="some-element">
<button class="my-button" id="foo">
 </button>
 </div>
Vignesh Raja
  • 7,927
  • 1
  • 33
  • 42
-1

Your code is actually Ok but you will need a way to add the button to the DOM for example if you are to append it to the body, You may have to do something like

document.body.appendChild(playButton)

You can as well add it to an existing element on the webpage

Jjagwe Dennis
  • 1,643
  • 9
  • 13
  • 1
    Of course I'm appending it to the DOM (I said in the question that the button works if I put some textContent to it.), I just didn't include it to the example, I'm sorry. Updated. So there has to be some – T.Poe Jul 19 '18 at 19:12