Our SVG viewer will have the following features:
- An editor that allows us to write, paste, and edit SVG code
- A validation mechanism that checks if the SVG Code is valid
- A preview area where we’ll see the SVG in real-time
- An export feature that will allow us to export the SVG
So, by the end of this tutorial, we’ll have something like this:
The SVG editor will have a text area to add, edit, or paste the SVG code.
1 |
<div class="editor"> |
2 |
<div class="editor-header">SVG Code Editor</div> |
3 |
<textarea
|
4 |
id="svgInput" |
5 |
placeholder="Paste your SVG code here and watch the magic happen..." |
6 |
></textarea>
|
7 |
</div>
|
The preview area will have a preview container where the current SVG code will be injected for preview.
1 |
<div class="preview"> |
2 |
<div class="preview-header">SVG Preview</div> |
3 |
<div class="preview-content"> |
4 |
<div id="previewContainer" class="preview-container"></div> |
5 |
</div>
|
6 |
</div>
|
HTML Markup
Okay, let’s start with the building blocks. The HTML markup will look like this:
1 |
<div class="main"> |
2 |
<header>
|
3 |
<h1>SVG Preview Tool</h1> |
4 |
<p>Edit, preview, and export clean, scalable vector art</p> |
5 |
</header>
|
6 |
<div class="container"> |
7 |
<div class="editor"> |
8 |
<div class="editor-header">SVG Code Editor</div> |
9 |
|
10 |
<textarea
|
11 |
id="svgInput" |
12 |
placeholder="Paste your SVG code here and watch the magic happen..." |
13 |
></textarea>
|
14 |
|
15 |
</div>
|
16 |
<div class="preview"> |
17 |
<div class="preview-header">SVG Preview</div> |
18 |
<div class="preview-content"> |
19 |
<div id="previewContainer" class="preview-container"></div> |
20 |
</div>
|
21 |
</div>
|
22 |
</div>
|
23 |
|
24 |
<button id="exportBtn">Export SVG</button> |
25 |
</div>
|
Styling with CSS
As you saw from the final demo, we want the editor and the preview to appear side by side on large screens and stack vertically on small devices. We’ll achieve this layout using Flexbox and media queries.
Let’s begin by applying some basic styles to the <body>
and <header>
elements as shown below.
1 |
@import url("https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap"); |
2 |
|
3 |
* { |
4 |
margin: 0; |
5 |
padding: 0; |
6 |
box-sizing: border-box; |
7 |
}
|
8 |
|
9 |
body { |
10 |
display: flex; |
11 |
min-height: 100vh; |
12 |
justify-content: center; |
13 |
padding: 20px; |
14 |
font-family: "DM Mono", monospace; |
15 |
}
|
16 |
|
17 |
header { |
18 |
max-width: 420px; |
19 |
text-align: center; |
20 |
margin-bottom: 40px; |
21 |
}
|
22 |
|
23 |
h1 { |
24 |
font-size: 30px; |
25 |
font-weight: 700; |
26 |
margin-bottom: 8px; |
27 |
}
|
28 |
|
29 |
header p { |
30 |
font-size: 18px; |
31 |
}
|
We’ll apply the following styles to ensure all elements are stacked vertically.
1 |
.main { |
2 |
display: flex; |
3 |
flex-direction: column; |
4 |
align-items: center; |
5 |
gap: 24px; |
6 |
width: 100%; |
7 |
max-width: 1000px; |
8 |
height: 90vh; |
9 |
min-height: 700px; |
10 |
margin-top: 50px; |
11 |
}
|
12 |
.container { |
13 |
display: flex; |
14 |
height: calc(100% - 84px); |
15 |
gap: 20px; |
16 |
width: 100%; |
17 |
}
|
We also want the text editor and the preview container to fill the available height of their parent containers.
1 |
.editor { |
2 |
border: 1px solid #7287f2; |
3 |
}
|
4 |
|
5 |
.editor, |
6 |
.preview { |
7 |
width: 50%; |
8 |
display: flex; |
9 |
flex-direction: column; |
10 |
border-radius: 16px; |
11 |
overflow: hidden; |
12 |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
13 |
}
|
14 |
|
15 |
.editor-header, |
16 |
.preview-header { |
17 |
padding: 12px 20px; |
18 |
font-weight: 600; |
19 |
font-size: 14px; |
20 |
text-align: center; |
21 |
width: 100%; |
22 |
color: white; |
23 |
|
24 |
}
|
25 |
|
26 |
textarea { |
27 |
/* width: 100%; */
|
28 |
height: 100%; |
29 |
border: none; |
30 |
padding: 20px; |
31 |
font-size: 13px; |
32 |
resize: none; |
33 |
background: #2e3138; |
34 |
color: white; |
35 |
overflow-y: auto; |
36 |
}
|
37 |
|
38 |
textarea:focus { |
39 |
outline: none; |
40 |
}
|
41 |
|
42 |
.preview-container { |
43 |
width: 100%; |
44 |
height: 100%; |
45 |
border-radius: 16px; |
46 |
background-color: #f9fafb; |
47 |
overflow-y: auto; |
48 |
}
|
49 |
|
50 |
.preview-content { |
51 |
flex: 1; |
52 |
padding: 16px; |
53 |
overflow: hidden; |
54 |
}
|
55 |
|
56 |
.svg-container { |
57 |
display: flex; |
58 |
justify-content: center; |
59 |
overflow: hidden; |
60 |
}
|
Finally, let’s style the export button, add styles for displaying error messages, and apply media queries for responsiveness.
1 |
.error-message { |
2 |
color: #dc2626; |
3 |
background: #fef2f2; |
4 |
border: 1px solid #fca5a5; |
5 |
padding: 16px; |
6 |
margin: 20px; |
7 |
border-radius: 6px; |
8 |
font-size: 13px; |
9 |
}
|
10 |
|
11 |
button { |
12 |
margin-top: 40px; |
13 |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
14 |
color: white; |
15 |
padding: 12px 30px; |
16 |
border: none; |
17 |
border-radius: 8px; |
18 |
cursor: pointer; |
19 |
width: 150px; |
20 |
}
|
21 |
|
22 |
@media (max-width: 768px) { |
23 |
body { |
24 |
padding: 20px; |
25 |
}
|
26 |
|
27 |
.main { |
28 |
width: 100%; |
29 |
height: 100vh; |
30 |
}
|
31 |
|
32 |
.container { |
33 |
flex-direction: column; |
34 |
height: 100%; |
35 |
}
|
36 |
|
37 |
.editor, |
38 |
.preview { |
39 |
width: 100%; |
40 |
height: 50%; |
41 |
}
|
42 |
}
|
Now the SVG tool interface looks like this:



JavaScript functionality
In this section, we’ll perform some SVG code validation to ensure that any SVG code added to the editor is parsed before being displayed.
We’ll also add a sample SVG code in the editor and display it in the preview area by default.
Let’s start by getting the elements from the DOM and assigning them to variables for easy access.
1 |
const svgInput = document.getElementById("svgInput"); |
2 |
const previewContainer = document.getElementById("previewContainer"); |
3 |
const exportBtn = document.getElementById("exportBtn"); |
SVG Code Validation
The next step is to ensure that the SVG code is valid before adding it for preview. Create a function called loadSVG()
that takes an SVG string as an argument.
Inside this function, we will first check if the SVG string is empty. If its empty, we’ll display an error message.
1 |
function loadSVG(svgCode) { |
2 |
previewContainer.innerHTML = ""; |
3 |
if (!svgCode.trim()) { |
4 |
showErrorMessage("Enter SVG code to see preview"); |
5 |
return; |
6 |
}}
|
The second form of validation will be done using the DOMParser
to ensure the SVG Code is well formatted XML code.
DOMParser
is an inbuilt interface in JavaScript that allows us to convert XML or HTML strings into a DOM Document object. Once the string is parsed into a DOM, you can query it using standard DOM methods like querySelector, etc.
To parse the XML, first create an instance of the DOMParser
API. Then, parse the SVG string using the ParseFromString()
method and set “image/svg+xml” as the MIME type.
1 |
const parser = new DOMParser(); |
2 |
const doc = parser.parseFromString(svgCode, "image/svg+xml"); |
Check for errors by querying the <parserror>
element. If there are no errors, we will extract the <svg>
element and inject it into the preview.
1 |
function loadSVG(svgCode) { |
2 |
previewContainer.innerHTML = ""; |
3 |
if (!svgCode.trim()) { |
4 |
showErrorMessage("Enter SVG code to see preview"); |
5 |
return; |
6 |
}
|
7 |
|
8 |
try { |
9 |
const parser = new DOMParser(); |
10 |
const doc = parser.parseFromString(svgCode, "image/svg+xml"); |
11 |
const parserError = doc.querySelector("parsererror"); |
12 |
if (parserError) |
13 |
throw new Error("XML parsing error: " + parserError.textContent); |
14 |
const svgElement = doc.querySelector("svg"); |
15 |
if (!svgElement) throw new Error("No valid SVG element found"); |
16 |
|
17 |
const container = document.createElement("div"); |
18 |
container.className = "svg-container"; |
19 |
container.innerHTML = svgCode; |
20 |
previewContainer.appendChild(container); |
21 |
} catch (error) { |
22 |
|
23 |
showErrorMessage("Invalid SVG code: " + error.message); |
24 |
}
|
25 |
}
|
Add event listeners
We now have a function that validates and displays the SVG code, so the next step is to ensure it runs before the SVG code in the input changes.
Add two event listeners to the textarea element as shown below:
1 |
svgInput.addEventListener("input", function () { |
2 |
loadSVG(this.value); |
3 |
});
|
4 |
svgInput.addEventListener("paste", function () { |
5 |
loadSVG(this.value); |
6 |
});
|
The input event will be triggered whenever you type, delete, or change the contents of the text area, while the paste event will be triggered when you paste the content to the text area.
Load sample SVG and export SVG
The final step is to ensure that we have a default SVG when the tool opens. This is great to ensure the user sees how the tool works.
Create a function called loadDefaultSVG()
which looks like this:
1 |
function loadDefaultSVG() { |
2 |
const sampleSvg = `<svg xmlns="https://www.w3.org/2000/svg" width="160" height="190" viewBox="0 0 60 60"><defs><style>.cls-1{fill:#87e64b;}</style></defs><circle class="cls-1" cx="25.56" cy="61.15" r="2.86"/><path class="cls-1" d="M42,41.65l-16.13,1.73c-.3.03-.45-.34-.21-.53l15.78-12.29c1.02-.84,1.68-2.14,1.4-3.54-.28-2.14-2.05-3.54-4.29-3.26l-17.15,2.51c-.3.04-.46-.34-.22-.53l17-12.98c3.35-2.61,3.63-7.73.56-10.71-2.79-2.79-7.27-2.7-10.06.09L1.29,30.01c-1.02,1.12-1.49,2.61-1.21,4.19.47,2.52,2.98,4.19,5.5,3.73l14.77-3.01c.32-.07.49.36.22.54l-16.38,10.49c-2.05,1.3-2.98,3.63-2.33,5.96.65,3.07,3.73,4.84,6.71,4.1l24.49-6.03c.28-.07.48.25.3.47l-3.82,4.72c-1.02,1.3.65,3.07,2.05,2.05l12.58-10.34c2.24-1.86.75-5.5-2.14-5.22h-.03Z"/></svg>`; |
3 |
|
4 |
svgInput.value = sampleSvg; |
5 |
loadSVG(sampleSvg); |
6 |
}
|
7 |
|
8 |
window.addEventListener("load", loadDefaultSVG); |
In the code above, we set a default SVG string as the value of the editor (in the textarea), then we call the loadSVG()
function which in turn renders the SVG in the preview area.
I’ve used the Envato “creative spark” for this example, but you can choose any default SVG you like
Export SVG
To export the SVG, we’ll package it as an SVG file and trigger a download when the export button is clicked.
1 |
function exportSVG() { |
2 |
const blob = new Blob([svgInput.value], { |
3 |
type: "image/svg+xml" |
4 |
});
|
5 |
const url = URL.createObjectURL(blob); |
6 |
const a = document.createElement("a"); |
7 |
a.href = url; |
8 |
a.download = "svg-viewer.svg"; |
9 |
document.body.appendChild(a); |
10 |
a.click(); |
11 |
document.body.removeChild(a); |
12 |
URL.revokeObjectURL(url); |
13 |
}
|
14 |
exportBtn.addEventListener("click", exportSVG); |
Final demo
And we’re done! Here’s a reminder of the final codepen demo:
We built a fully functional SVG viewer using HTML, CSS, and JavaScript. This simple, yet powerful tool will allow you to preview and export your SVG graphics for use in your projects.