or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# @visx/text

1

2

@visx/text provides an enhanced SVG Text component for React applications that extends the basic SVG text element with advanced text layout capabilities including automatic word-wrapping when width is specified, vertical alignment through the verticalAnchor prop, text rotation via the angle prop, and scale-to-fit functionality.

3

4

## Package Information

5

6

- **Package Name**: @visx/text

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @visx/text`

10

11

## Core Imports

12

13

```typescript

14

import { Text, useText, getStringWidth } from "@visx/text";

15

import type { TextProps, WordsWithWidth, compareFunction } from "@visx/text";

16

```

17

18

For CommonJS:

19

20

```javascript

21

const { Text, useText, getStringWidth } = require("@visx/text");

22

```

23

24

## Basic Usage

25

26

```typescript

27

import React from "react";

28

import { Text } from "@visx/text";

29

30

// Simple text with vertical alignment

31

const App = () => (

32

<svg width={400} height={300}>

33

<Text

34

x={50}

35

y={50}

36

verticalAnchor="start"

37

fontSize={16}

38

fill="black"

39

>

40

Hello world

41

</Text>

42

</svg>

43

);

44

45

// Text with word wrapping

46

const WrappedTextExample = () => (

47

<svg width={400} height={300}>

48

<Text

49

x={50}

50

y={50}

51

width={200}

52

verticalAnchor="start"

53

fontSize={14}

54

fill="blue"

55

>

56

This is a long text that will be wrapped automatically when the width constraint is applied.

57

</Text>

58

</svg>

59

);

60

61

// Rotated and scaled text

62

const AdvancedTextExample = () => (

63

<svg width={400} height={300}>

64

<Text

65

x={200}

66

y={150}

67

width={180}

68

angle={45}

69

scaleToFit="shrink-only"

70

textAnchor="middle"

71

verticalAnchor="middle"

72

fontSize={16}

73

fill="red"

74

>

75

Rotated and fitted text

76

</Text>

77

</svg>

78

);

79

```

80

81

## Architecture

82

83

@visx/text is built around three core components:

84

85

- **Text Component**: The main React component that renders enhanced SVG text elements with advanced layout features

86

- **useText Hook**: Internal hook that handles all text layout calculations including line breaking, positioning, and transforms

87

- **getStringWidth Utility**: Browser-based text measurement function using hidden SVG elements for accurate pixel width calculations

88

89

The architecture follows a separation of concerns where the Text component handles rendering while useText manages all layout computation, and getStringWidth provides the foundational measurement capabilities.

90

91

## Capabilities

92

93

### Text Component

94

95

The main React component providing enhanced SVG text rendering with word-wrapping, alignment, rotation, and scaling features.

96

97

```typescript { .api }

98

/**

99

* Enhanced SVG Text component with advanced layout features

100

* @param props - TextProps configuration object

101

* @returns JSX.Element - SVG element containing positioned text

102

*/

103

function Text(props: TextProps): JSX.Element;

104

105

type TextOwnProps = {

106

/** CSS class name to apply to the SVGText element */

107

className?: string;

108

/** Whether to scale font size to fit the specified width (default: false) */

109

scaleToFit?: boolean | 'shrink-only';

110

/** Rotation angle in degrees */

111

angle?: number;

112

/** Horizontal text anchor position (default: 'start') */

113

textAnchor?: 'start' | 'middle' | 'end' | 'inherit';

114

/** Vertical text anchor position (default: 'end' in useText hook, undefined in Text component) */

115

verticalAnchor?: 'start' | 'middle' | 'end';

116

/** Inline styles for the text (used in text measurement calculations) */

117

style?: React.CSSProperties;

118

/** Ref for the SVG container element */

119

innerRef?: React.Ref<SVGSVGElement>;

120

/** Ref for the text element */

121

innerTextRef?: React.Ref<SVGTextElement>;

122

/** X position of the text */

123

x?: string | number;

124

/** Y position of the text */

125

y?: string | number;

126

/** X offset from the position (default: 0) */

127

dx?: string | number;

128

/** Y offset from the position (default: 0) */

129

dy?: string | number;

130

/** Line height for multi-line text (default: '1em') */

131

lineHeight?: React.SVGAttributes<SVGTSpanElement>['dy'];

132

/** Cap height for vertical alignment calculations (default: '0.71em') */

133

capHeight?: React.SVGAttributes<SVGTSpanElement>['capHeight'];

134

/** Font size */

135

fontSize?: string | number;

136

/** Font family */

137

fontFamily?: string;

138

/** Text fill color */

139

fill?: string;

140

/** Maximum width for word wrapping (approximate, words are not split) */

141

width?: number;

142

/** Text content to render */

143

children?: string | number;

144

};

145

146

type TextProps = TextOwnProps & Omit<React.SVGAttributes<SVGTextElement>, keyof TextOwnProps>;

147

148

/**

149

* Note: TextProps extends all standard SVG text element attributes including:

150

* - Standard SVG styling: stroke, strokeWidth, opacity, etc.

151

* - Event handlers: onClick, onMouseOver, onMouseOut, etc.

152

* - Accessibility attributes: aria-*, role, etc.

153

* Only the custom @visx/text-specific props are documented above.

154

*/

155

```

156

157

**Usage Examples:**

158

159

```typescript

160

import React from "react";

161

import { Text } from "@visx/text";

162

163

// Basic text positioning

164

<Text x={100} y={50} fontSize={16} fill="black">

165

Simple text

166

</Text>

167

168

// Word-wrapped text

169

<Text

170

x={50}

171

y={50}

172

width={200}

173

fontSize={14}

174

verticalAnchor="start"

175

lineHeight="1.2em"

176

>

177

This text will wrap to multiple lines when it exceeds 200 pixels width

178

</Text>

179

180

// Rotated text with scaling

181

<Text

182

x={150}

183

y={100}

184

width={100}

185

angle={30}

186

scaleToFit="shrink-only"

187

textAnchor="middle"

188

verticalAnchor="middle"

189

fontSize={16}

190

>

191

Rotated scaled text

192

</Text>

193

194

// Styled text with refs and standard SVG attributes

195

<Text

196

x={200}

197

y={150}

198

className="custom-text"

199

style={{ fontWeight: 'bold' }}

200

innerRef={svgRef}

201

innerTextRef={textRef}

202

fill="#ff6b6b"

203

stroke="black"

204

strokeWidth={0.5}

205

opacity={0.9}

206

onClick={(e) => console.log('Text clicked')}

207

>

208

Styled text with refs

209

</Text>

210

```

211

212

### Text Layout Hook

213

214

React hook that handles text layout calculations including line breaking, vertical positioning, and transform generation.

215

216

```typescript { .api }

217

/**

218

* Hook for calculating text layout including line breaks and positioning

219

* @param props - TextProps configuration

220

* @returns Object containing layout calculation results

221

*/

222

function useText(props: TextProps): {

223

wordsByLines: WordsWithWidth[];

224

startDy: string;

225

transform: string;

226

};

227

228

interface WordsWithWidth {

229

/** Array of words in this line */

230

words: string[];

231

/** Calculated pixel width of the line (optional) */

232

width?: number;

233

}

234

```

235

236

**Usage Example:**

237

238

```typescript

239

import React from "react";

240

import { useText } from "@visx/text";

241

import type { TextProps } from "@visx/text";

242

243

const CustomTextComponent = (props: TextProps) => {

244

const { wordsByLines, startDy, transform } = useText(props);

245

const { x = 0, fontSize, textAnchor = 'start' } = props;

246

247

return (

248

<svg>

249

<text transform={transform} fontSize={fontSize} textAnchor={textAnchor}>

250

{wordsByLines.map((line, index) => (

251

<tspan

252

key={index}

253

x={x}

254

dy={index === 0 ? startDy : props.lineHeight || '1em'}

255

>

256

{line.words.join(' ')}

257

</tspan>

258

))}

259

</text>

260

</svg>

261

);

262

};

263

```

264

265

### String Width Measurement

266

267

Utility function for measuring the pixel width of text strings using browser SVG measurement.

268

269

```typescript { .api }

270

/**

271

* Measures the pixel width of a text string using SVG measurement

272

* Memoized using lodash.memoize with cache key: `${str}_${JSON.stringify(style)}`

273

* Creates a hidden SVG element with id '__react_svg_text_measurement_id' for measurements

274

* @param str - Text string to measure

275

* @param style - Optional CSS style object to apply during measurement

276

* @returns Pixel width of the text using getComputedTextLength(), or null if measurement fails (non-browser environment, DOM errors)

277

*/

278

function getStringWidth(str: string, style?: object): number | null;

279

```

280

281

**Usage Example:**

282

283

```typescript

284

import { getStringWidth } from "@visx/text";

285

286

// Basic width measurement

287

const width = getStringWidth("Hello world");

288

console.log(width); // e.g., 77.5

289

290

// Width with custom styling

291

const styledWidth = getStringWidth("Bold text", {

292

fontFamily: 'Arial',

293

fontSize: '16px',

294

fontWeight: 'bold'

295

});

296

console.log(styledWidth); // e.g., 89.2

297

298

// Handle potential measurement failures

299

const safeWidth = getStringWidth("Some text") || 0;

300

```

301

302

## Types

303

304

### Comparison Function Type

305

306

```typescript { .api }

307

/**

308

* Generic type for comparison functions used in memoization

309

* @param prev - Previous value (may be undefined)

310

* @param next - Next value to compare

311

* @returns Boolean indicating if values are equal

312

*/

313

type compareFunction<T> = (prev: T | undefined, next: T) => boolean;

314

```

315

316

## Platform Requirements

317

318

- **Browser Environment**: Requires DOM access for text measurement via `document`

319

- **React**: Version 16.3.0 or higher

320

- **SVG Support**: Requires SVG rendering capabilities

321

322

## Error Handling

323

324

- **getStringWidth**: Returns `null` if measurement fails (e.g., in non-browser environments)

325

- **Text Component**: Safely handles invalid x/y coordinates by not rendering text

326

- **useText**: Returns empty wordsByLines array for invalid positioning values

327

328

## Implementation Details

329

330

### Text Processing

331

332

- **Word Splitting**: Text is split using the regex `/(?:(?!\u00A0+)\s+)/` which preserves non-breaking spaces (`\u00A0`) while splitting on other whitespace

333

- **Space Width Calculation**: Uses non-breaking space (`\u00A0`) for space width measurements to ensure consistent spacing

334

- **Line Breaking**: Words are never split - line breaks only occur between complete words

335

- **Width Validation**: X and Y coordinates must be finite numbers or valid strings (for percentage values)

336

337

### Transform Generation

338

339

- **Scale-to-fit**: When enabled, creates a matrix transform using the first line's width as reference

340

- **Rotation**: Applied around the specified x,y coordinates as the rotation center

341

- **Transform Order**: Scaling is applied before rotation in the transform chain

342

343

### SVG Container

344

345

- **Container Element**: Text is wrapped in an SVG element with `overflow: 'visible'` style

346

- **Positioning**: Container uses dx/dy for offset positioning from the base x/y coordinates

347

348

## Performance Considerations

349

350

- **Text Measurement**: getStringWidth is memoized using lodash.memoize with string and style as cache keys

351

- **Layout Calculations**: useText uses React.useMemo to prevent unnecessary recalculations

352

- **DOM Elements**: Hidden SVG measurement element is reused across all getStringWidth calls

353

- **Conditional Processing**: Layout calculations only run when width or scaleToFit props are provided