SVG with jsx without React

Aleks
2 min readMar 11, 2018

In the previous article I described my experience using JSX without React, it was a good experience overall and gave me a better understanding of what React does behind scenes, superficially talking of course.

But that was not the complete experience, implementing the company logo was part of that whole and it was a very SVG focused task.

The first difference that calls my attention is document.createElementNS stands for Name-Space, meaning that SVG elements need to be created like this:

const ns = 'http://www.w3.org/2000/svg'
const svg = document.createElementNS(ns, 'svg')

To understand the problem namespaces are trying to solve, consider file extensions. 3-letter file extensions have done a really bad job of describing the content of files. They’re ambiguous and don’t carry version info. XML namespaces use a larger space of strings, URIs, to solve the same problem, and use short prefixes so you can succinctly mix multiple kinds of XML in the same document.

That functionality was implemented asking if the tag was either path, svg or other svg related tags to apply the http://www.w3.org/2000/svg name space.

function isSVG(element) {
const patt = new RegExp('^' + element + '$', 'i')
const SVGTags = ['path', 'svg', 'use', 'g' ...]
return SVGTags.some(tag => patt.test(tag))
}
...const element = isSVG(tag)
? document.createElementNS('http://www.w3.org/2000/svg', tag)
: document.createElement(tag)

and the previous Object.assign to merge the attrs stopped working after the transform attribute was found because is a read-only property; to fix that setAttribute() was completely necessary (commit).

for (const prop in attrs) {
if (attrs.hasOwnProperty(prop)) {
element.setAttribute(prop, attrs[prop])
}
}

Always with Style (optional)

Sooner than later I found myself dealing with icons and logos that include inline styles, is not the cleanest implementation but if your fellow designers follow those practices is not impossible to support, if you don’t need it you’re good to go, give it a try to the npm library jsx-render .

In my case I want a piece of the action creating the function to process inline styles (commit)

function objectToStyleString(styles) {
return Object.keys(styles)
.map(prop => `${prop}: ${styles[prop]}`)
.join(';')
}
...if (prop === 'style') {
element.style = objectToStyleString(attrs[prop])
}

The example of what’s possible with this 60 lines here is a small svg

const Logo = () => (
<svg
id="Layer_1"
data-name="Layer 1"
style={{ 'min-width': '110px', height: '40px', width: '140px' }}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 141 41"
>
<title>Logo Title Tag</title>
<g>
<path
d="M241.74,421.43v-41h28.61v41H241"
transform="translate(-241.74 -380.43)"
style={{ fill: '#ffcd05' }}
/>
<g>
<path
d="M287.85,410.76v5.89a11.23,11.23,0,0,1-4.06.88c-4.2,0-6.85-3.26-6.85-7.46"
transform="translate(-241.74 -380.43)"
style={{ fill: '#ffffff' }}
/>
</g>
</g>
</svg>
)

Conclusions

  • SVG support was easier than what I was expecting
  • Implement styles might be more complicated if prefixes are included, so PRs are welcome
  • Combining last article and this one you can create a pretty solid alpha in 60 lines to render almost the same things that you can with stateless react elements.

--

--