If you want to display text inside a rect element you should put them both in a group with the text element coming after the rect element ( so it appears on top ). Is there a way to not have to manually set height and width on the rect?
In SVG, text is rendered with the <text> element. The simplest example of a <text> element is one that uses just x and y attributes to place it. Text is rendered by default with a black fill and no outline.
The text-anchor attribute is used to align (start-, middle- or end-alignment) a string of pre-formatted text or auto-wrapped text where the wrapping area is determined from the inline-size property relative to a given point. This attribute is not applicable to other types of auto-wrapped text.
Right-click the text box for which you want to set vertical alignment. On the shortcut menu, click Format Text Box. In the Format Text Box dialog box, click the Text Box tab. In the Vertical alignment box, select Top, Middle, or Bottom.
An easy solution to center text horizontally and vertically in SVG:
x="50%" y ="50%"
.x
would be the x
of that element + half its width (and similar for y
but with the height).text-anchor
property to center the text horizontally with the value middle
:middle
The rendered characters are aligned such that the geometric middle of the resulting rendered text is at the initial current text position.
dominant-baseline
property to center the text vertically with the value middle
(or depending on how you want it to look like, you may want to do central
)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;
}
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.
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>
The previous answers gave poor results when using rounded corners or stroke-width
that's >1 . For example, you would expect the following code to produce a rounded rectangle, but the corners are clipped by the parent svg
component:
<svg width="200" height="100">
<!--this rect should have rounded corners-->
<rect x="0" y="0" rx="5" ry="5" width="200" height="100" stroke="red" stroke-width="10px" fill="white"/>
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CLIPPED BORDER</text>
</svg>
Instead, I recommend wrapping the text
in a svg
and then nesting that new svg
and the rect
together inside a g
element, as in the following example:
<!--the outer svg here-->
<svg width="400px" height="300px">
<!--the rect/text group-->
<g transform="translate(50,50)">
<rect rx="5" ry="5" width="200" height="100" stroke="green" fill="none" stroke-width="10"/>
<svg width="200px" height="100px">
<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CORRECT BORDER</text>
</svg>
</g>
<!--rest of the image's code-->
</svg>
This fixes the clipping problem that occurs in the answers above. I also translated the rect/text group using the transform="translate(x,y)"
attribute to demonstrate that this provides a more intuitive approach to positioning the rect/text on-screen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With