How to place and center text in an SVG rectangle
SVG 1.2 Tiny added text wrapping, but most implementations of SVG that you will find in the browser (with the exception of Opera) have not implemented this feature. It's typically up to you, the developer, to position text manually.
The SVG 1.1 specification provides a good overview of this limitation, and the possible solutions to overcome it:
Each ‘text’ element causes a single string of text to be rendered. SVG performs no automatic line breaking or word wrapping. To achieve the effect of multiple lines of text, use one of the following methods:
- The author or authoring package needs to pre-compute the line breaks and use multiple ‘text’ elements (one for each line of text).
- The author or authoring package needs to pre-compute the line breaks and use a single ‘text’ element with one or more ‘tspan’ child elements with appropriate values for attributes ‘x’, ‘y’, ‘dx’ and ‘dy’ to set new start positions for those characters who start new lines. (This approach allows user text selection across multiple lines of text -- see Text selection and clipboard operations.)
- Express the text to be rendered in another XML namespace such as XHTML [XHTML] embedded inline within a ‘foreignObject’ element. (Note: the exact semantics of this approach are not completely defined at this time.)
http://www.w3.org/TR/SVG11/text.html#Introduction
As a primitive, text wrapping can be simulated by using the dy
attribute and tspan
elements, and as mentioned in the spec, some tools can automate this. For example, in Inkscape, select the shape you want, and the text you want, and use Text -> Flow into Frame. This will allow you to write your text, with wrapping, which will wrap based on the bounds of the shape. Also, make sure you follow these instructions to tell Inkscape to maintain compatibility with SVG 1.1:
https://wiki.inkscape.org/wiki/Frequently_asked_questions#What_about_flowed_text.3F
Furthermore, there are some JavaScript libraries that can be used to dynamically automate text wrapping: https://old.carto.net/papers/svg/textFlow/
It's interesting to note CSVG's solution to wrapping a shape to a text element (e.g. see their "button" example), although it's important to mention that their implementation is not usable in a browser: https://users.monash.edu/~clm/csvg/about.html
I'm mentioning this because I have developed a CSVG-inspired library that allows you to do similar things and does work in web browsers, although I haven't released it yet.
An easy solution to center text horizontally and vertically in SVG:
Set the position of the text to the absolute center of the element in which you want to center it:
- If it's the parent, you could just do
x="50%" y ="50%"
. - If it's another element,
x
would be thex
of that element + half its width (and similar fory
but with the height).
- If it's the parent, you could just do
Use the
text-anchor
property to center the text horizontally with the valuemiddle
:middle
The rendered characters are aligned such that the geometric middle of the resulting rendered text is at the initial current text position.
Use the
dominant-baseline
property to center the text vertically with the valuemiddle
(or depending on how you want it to look like, you may want to docentral
)
Here is a simple demo:
<svg width="200" height="100">
<rect x="0" y="0" width="200" height="100" stroke="red" stroke-width="3px" fill="white"/>
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">TEXT</text>
</svg>
You can also use this with CSS if you want to apply it to many elements. For example:
svg text{
text-anchor: middle;
dominant-baseline: middle;
}
If you are creating the SVG programmatically you can simplify it and do something like this:
<g>
<rect x={x} y={y} width={width} height={height} />
<text
x={x + width / 2}
y={y + height / 2}
dominant-baseline="middle"
text-anchor="middle"
>
{label}
</text>
</g>