How To Style and Position SVG Text With The tspan Element

The SVG text element allows you to easily position and style text, but what do you do if you want to position and style different parts of the text differently? Do you need to create multiple text elements? Nope. There’s an easier way.

The last couple of weeks we’ve been looking at the SVG text element and exploring what we can do to text using the different attributes available to us.

The <text> element isn’t the only element we can work with when working with SVG text, however. Today and next week I want to talk about two more SVG elements that you’ll use in combination with the <text> element. I want to talk about the <tspan> and <tref> elements.

The tspan Element

You can think of the <tspan> element as a span for SVG text. You can wrap part or all of you SVG text inside a <tspan> to give you greater control over its display and to position different lines or snippets of text relative to each other.

Let’s start with a simple example.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="240" y="120">  
    <tspan>SVG</tspan>  
    <tspan>SVG</tspan>  
  </text>  
</svg>

Hopefully most of the code here is familiar to you after reading the previous two posts in this series. I created an <svg> element, defined the dimensions of the SVG viewport and added a red outline so we can see its boundaries. I also bumped up the font-size a bit and set the overflow to visible so we can see any text that displays outside of the viewport.

I positioned a text element at (240,120) and inside created two tspans, each containing the text “SVG” inside. Here’s how it displays.

SVG SVG

The text in the tspans displays inline one after the other, which is how they would have displayed directly inside the text element with a space between them.

Things get interesting once you know that the same attributes that are available to you on the <text> element are also available on the <tspan> element.

Let’s change the position of the second tspan by setting its x and y coordinates. So we can tell the two tspans apart I added numbers to the text.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="240" y="120">  
    <tspan>SVG 1</tspan>  
    <tspan x="10" y="10">SVG 2</tspan>  
  </text>  
</svg>

I moved the second tspan to a position (10,10). Because x and y are absolute positions, these values place SVG 2 just to the right of the left edge of the viewport and also about halfway above and below the top edge.

SVG 1SVG 2

You might remember from the previous posts that the y position is the position of the baseline and not the top or bottom of the text.

For relative positioning we can use dx and dy as in the next example.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="240" y="120">  
    <tspan>SVG 1</tspan>  
    <tspan dx="50,10,10,0,5" dy="50,10,10,10">SVG 2</tspan>  
  </text>  
</svg>

Here I used a list of coordinates on the second tspan. Each character is positioned relative to the one before it.

SVG 1SVG 2

In the case of the very first character, the position is relative to where it would be located if no dx or dy were given.

Because each tspan is its own element you can style the text inside them differently in addition to positioning them in different locations.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="240" y="120">  
    <tspan>SVG 1</tspan>  
    <tspan dx="50,10,10,0,5" dy="50,10,10,10" fill="red">SVG 2</tspan>  
  </text>  
</svg>

Here I styled SVG 2 to have a red fill instead of the default black. Again think of a tspan like you would a regular span, except that it’s specifically used inside an SVG <text> element.

SVG 1SVG 2

You can have one tspan display directly below another by giving both the same x value and giving the second one a dy value that positions it below the first.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="280" y="80">  
    <tspan>SVG 1</tspan>  
    <tspan x="280" dy="24" fill="red">SVG 2</tspan>  
  </text>  
</svg>

Here I set the second tspan to have an x-coordinate equal to what was set on the text element and I gave it a dy value of 24 to drop it directly below the first tspan.

Note: I could have also set the position absolutely using y instead of dy.

SVG 1SVG 2

Again all the attributes we saw last week for the text element can be used on the tspan. One thing to note is that any attribute set on the text element propagates to the tspans within it.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="280" y="80" rotate="10">  
    <tspan>SVG 1</tspan>  
    <tspan x="280" dy="36" fill="red">SVG 2</tspan>  
  </text>  
</svg>

Here I rotated the text element 10 degrees and you can see that every character in both tspans has been rotated 10 degrees even though I didn’t explicitly rotate either of the tspans.

SVG 1SVG 2

That’s probably not surprising, but what might be is, if you want to set the text in the first tspan back to normal, you don’t set its rotation to –10 to compensate. Here’s how that would look.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="280" y="80" rotate="10">  
    <tspan rotate="-10">SVG 1</tspan>  
    <tspan x="280" dy="36" fill="red">SVG 2</tspan>  
  </text>  
</svg>

The rotation on the tspan overrides what’s been set on the text element and is now rotated –10 degrees, which isn’t what we wanted.

SVG 1SVG 2

If you want it upright again you would set the rotation to 0.

1
2
3
4
5
6
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">  
  <text x="280" y="80" rotate="10">  
    <tspan rotate="0">SVG 1</tspan>  
    <tspan x="280" dy="36" fill="red">SVG 2</tspan>  
  </text>  
</svg>

And now the text in the first tspan is once again upright.

SVG 1SVG 2

There are a couple more attributes to get to as well as the tref element, but let’s stop here and pick things up again next week.

Closing Thoughts

The SVG tspan element functions similarly to an ordinary HTML span element. By wrapping a tspan around part of the text you want to display, you can style and position that text independently of any text not in that tspan.

All the attributes available to the text element are also available to tspans as are fills and strokes and any of the attributes you can add to any SVG element.

The value of any attribute you add to a text element will propagate down to the tspans within it. If you don’t want one to propagate, you set a new value on the tspan that overrides the value on the text element.

Next week, I’ll continue with the textLength and lengthAdjust attributes and then I’ll introduce the <tref> element which lets us reuse SVG text across different text and tspan elements.

Download a free sample from my book, Design Fundamentals.

2 comments

  1. Nice article and thank you for your time 😀
    would you please help me in a small svg text spacing problem:
    my code is something like:

    te
    xt

    how can i remove the white space between the two without setting the x and y on them (because i have some animation on #myText and i really don’t want to duplicate the animation for every )

    • my bad, i had some problems while updating the page that’s why “relative positioning” didn’t work and now a dx=”-10″ solved the problem, thank you again for the great article <3

Leave a Reply

Your email address will not be published. Required fields are marked *