The A-to-Z of Framer’s Text Layers

Tips, tricks and everything in between. An exhaustive guide to working with type in Framer.

Tes Mat
Framer
18 min readAug 15, 2017

--

There’s a 🇰🇷 Korean translation of this post by designer Kenny Hong.

Last update: May 1, 2018.

Combining Code and Design

With the launch of Dynamic Type, text blocks created in Framer Design became real Text Layers. In addition to updating the text in Code with template tags, you can now change how the text looks.

In this post I’ll give an overview of all Text Layer properties, show which ones can be animated, and share some tips and tricks.

If you still don’t have Framer but want to follow along, make sure to download the free 14-day trial.

By the way, you can, of course, still create Text Layers in Code as well. There’s a Snippet; see Layer > Text in the Snippet menu.

myText = new TextLayer
text: "Hello World"
fontSize: 64
point: Align.center

Contents

  1. Setting and changing the text
  2. Templating
  3. Auto-sizing
  4. Padding
  5. Truncation
  6. Color
  7. Background Color
  8. Font Size
  9. Font Family
  10. Font Weight
  11. Font Style
  12. Line Height
  13. Font
  14. Text Align
  15. Shadow Color
  16. Shadow X
  17. Shadow Y
  18. Shadow Blur
  19. Letter Spacing
  20. Word Spacing
  21. Text Transform
  22. Text Decoration
  23. Text Indent
  24. Direction
  25. Setting other CSS properties

1. Setting and changing the text

Changing the .text

With .text you set the text for the layer — no surprises here. And, of course, many different languages and scripts are supported.

  • Framer docs: text.text
  • Can be ✅ set in Framer Design

A few remarks about these projects

Almost all example Text Layers got a fixed size in Design. I enabled Auto Height so that they can resize to accommodate changes.

# Adjust the Text Layer's height automatically theTextLayer.autoHeight = yes

I also gave most of them a light gray background (another thing you have to do in Code), so that you can see the actual size of the layer.

# Visible background for the Text Layer
theTextLayer.backgroundColor = "#eee"

The example sentences are from Google Fonts. Apparently they’re quotes from different novels.

Multi-line text

When setting a "string" you always enclose it in quotation marks. But what if you have more than just one line of text?

layer.text = "This is a new line. And here’s a second line!"

It’s simple: you use triple """ quotation marks.

layer.text = """
This is a new line.
Here’s a second line.
And even a third!
"""

… or you use the ‘newline’ character (\n):

layer.text = "This is a new line.\nHere’s a second line.\nAnd even a third!"

And when the lines in the original text differ in styling, those styles will also be maintained.

Search and replace

You can search for a string in the text and replace it with something else.

layerA = new TextLayer
text: "Text Layers can be created in Framer Code."
layerA.textReplace("Framer Code", "Framer Code AND Framer Design")

And when there are more than one occurrence of the same string, they will all be replaced.

text.textReplace("the", "da")

This textReplace() function is built upon JavaScript’s String.replace(), so you can also use Regular Expressions.

But before you dive in to the RegEx documentation, first take a look at Templating below!

2. Templating

With templates you can pinpoint exactly which part of the text you want to replace by inserting tags. Template tags are wrapped in {} and can be styled just like any other text.

theTextLayer.template =
pet: "🐙"
hobby: "🎺"
number: 10
gift: "🍪"

There’s a shortcut for when your Text Layer has just one tag, or when you only want to set the first tag:

theTextLayer.template = "🐙"

You can also animate to a new value. It will not make a difference for text, but numbers will be animated. When you first animate to a number, it will count up from zero. Afterwards, it will count up or down to the new value.

theTextLayer.animate
template:
number: Utils.randomNumber 1, 20

(From the example prototype above: {number} gets animated to a randomNumber between 1 and 20.)

Swapping between styles

Templating can (sometimes) be used as a way to switch between different styles. You can prepare different stylings for a text block and then swap them in and out.

For example, most of these example prototypes have a Text Layer named title that contains {v} and {d} tags. The {v} text is plain white, while the {d} text is 60% transparent. I always hide one of them by giving it an empty string:

title.template =
v: ""
d: "«default»"

Template formatter

With the templateFormatter you can set how numbers should appear (or animate). You’ll often use it to limit the amount of decimals.

In the formatter, you give your existing template tag a function that does something to the value.

The first counter above doesn’t have a template formatter; the {s} tag is simply animated to the number 5 (over a duration of five seconds). That’s why we also see the decimal values roll by.

textLayer1.animate
template:
s: 5

The second counter has two tags: {s} and {ms}.

  • For the ‘seconds’ tag {s} the value is formatted to a number without decimals, using Utils.Round.
  • And the ‘milliseconds’ tag {ms} will show 1/1000th of every second (using the % remainder operator).
textLayer2.templateFormatter = 
s: (value) ->
Utils.round value
ms: (value) ->
Utils.round ( value * 1000 ) % 1000

The third counter’s template formatter takes the value in seconds and converts it into minutes and numbers, with a : between them.

textLayer3.templateFormatter =    m: (value) ->
minutes = Math.floor(value / 60)
seconds = Math.round(value % 60)

if seconds < 10
seconds = "0#{seconds}"

return "#{minutes}:#{seconds}"

It uses a return statement to define what exactly should be returned by the function. (By default, CoffeeScript will return the last value.)

Template formatter also has a shortcut for when your Text Layer has just one tag (or you only want to format the first tag):

textLayer1.templateFormatter = (value) ->
Utils.round value

3. Auto-sizing

When you make changes to the text (as in the former example projects), and also when you change the text’s size or line height (as in the upcoming examples), your Text Layer must be able to resize. (And that’s why all these example projects have resizing enabled.)

It’s best to enable auto-sizing in Code because that’s where you’ll have more options.

In Design, you can give a text block a fixed size …

or set it to auto-size in both directions:

But in Code you can decide in which direction the text should resize.

Auto Height

When you enable autoHeight the Text Layer will maintain the width you gave it, but change its height to make room for the text.

text.autoHeight = yes

To illustrate the difference, this is the behavior of a layer that was given a fixed width and height in Design:

Tapping the ‘more text’ button will add an extra paragraph:

# More text
buttonB.onTap ->
theTextLayer.text = """Then came the night of the first falling star. It was seen early in the morning, rushing over Winchester eastward, a line of flame high in the atmosphere. Hundreds must have seen it, and taken it for an ordinary falling star. Albin described it as leaving a greenish streak behind it that glowed for some seconds. Denning, our greatest authority on meteorites, stated that the height of its first appearance was about ninety or one hundred miles. It seemed to him that it fell to earth about one hundred miles east of him.
I was at home at that hour and writing in my study; and although my French windows face towards Ottershaw and the blind was up (for I loved in those days to look up at the night sky), I saw nothing of it."""

… but nothing will change because the Text Layer is not set to adapt its height (nor its width).

(A Text Layer will mask the text it contains — its clip is always on.)

And here’s what happens when autoHeight is enabled:

Now that the text block resizes, I can also adjust the position of the — • — underneath it by looking at the Text Layer’s maxY:

# Place the line under the text
lineUnderText.y = theTextLayer.maxY + 20

Auto Width

There’s also autoWidth, for when the text block should stick to a certain height, and you only want its width to adapt.

text.autoWidth = yes

But there’s a limit: a Text Layer will never become wider than its parent layer, or when there’s no parent, wider than the screen.

Auto Everything

And if you want a text block to resize both vertically and horizontally, you can switch on its autoSize

text.autoSize = yes

… but that’s, of course, the same as the default behavior in Design:

One more thing: Setting a layer’s width or height will disable its auto-sizing for that direction. Remember that width and height are also changed when you set size or frame.

4. Padding

This is the space between the text itself and the edge of the layer. Adding more padding will make the Text Layer grow, in whichever direction it can.

So when using padding you should give the layer the possibility to resize, by enabling autoHeight or autoWidth.

You can set padding globally, for all four sides:

textA = new TextLayer
text: "Hello World"
padding: 20

… or for each side individually:

textB = new TextLayer
text: "Hello World"
padding:
top: 40
left: 20
bottom: 40
right: 20

… or use horizontal to set left and right at the same time, and do the same for top and bottom with vertical:

textC = new TextLayer
text: "Hello World"
padding:
horizontal: 80
vertical: 40

By using vertical and horizontal padding together with a background color you can convert the humble Text Layer into a button (see the examples below, under Background Color).

5. Truncation

So much text, too much text, it doesn’t fit …

Text Overflow

Setting textOverflow to "ellipsis" will signal overflowing text with an ‘…’. The other option, "clip", will just cut off the text at the first line.

You need to set a fixed height for this to work, so don’t use autoHeight or text.autoSize on a text block that you want to truncate.

The height of your layer defines how many lines will be shown. It can be tricky to find the correct height, though, so here’s a tip:

Pro tip: Use fontSize and lineHeight to calculate the correct height for a certain amount of lines:

textLayer.height = ( textLayer.fontSize * textLayer.lineHeight ) * 2

Truncate

There’s also truncate; setting it to yes will let the text overflow with an ellipsis.

textA = new TextLayer
text: "Very long text, that definitely needs some truncation, because it’ll never fit on this small mobile screen."
truncate: yes

6. Color

You set the color of the text itself on .color, and just like any other color property in Framer, you can animate it.

The default color of a Text Layer created in Code is a light gray: "#888".

  • Framer docs: layer.color
  • Can be ✅ set in Framer Design
  • Can be ✅ animated

7. Background Color

Text Layers are transparent by default, but just like common layers you can give them a backgroundColor.

Text Layers are perfect for making buttons with different states. You can give your buttons a fixed size using width and height, but know that you can use padding and lineHeight to create flexible buttons that resize automatically.

See the project below for examples of all three techniques: one with padding, one with line height, and a third one with a fixed size.

And gradients!

As shown by the third button above, you can also set and animate gradients.

8. Font Size

Well, the size of the text … this stuff is easy, right?

Note that it’s a points value (so no px, em or % values like in CSS).

Decimal values can be used, though, like halves (e.g., 10.5) to change the font size by only a pixel.

  • Framer docs: text.fontSize
  • Can be ✅ set in Framer Design
  • Can be ✅ animated

9. Font Family

When you don’t set fontFamily (on a Text Layer created in Code), Framer will use the platform’s default typeface: San Francisco on Apple devices, Roboto on Android, etc.

Just like in CSS, you can give alternatives for when a font is not available. In fact, Framer’s default for Google devices actually says:

fontFamily: "Roboto, Helvetica Neue"

So when Roboto is not installed it will fall back to Helvetica Neue.

Here’s an example of how Framer falls back to an alternative font: one of the examples in the above project says …

fontFamily: "Brush Script MT, cursive"

… but there’s no Brush Script on iOS devices. There’s a default cursive typeface, though, so that’s the one you’ll see.

Loading Google Fonts

You can load any font from Google’s catalogue by passing its name to Utils.loadWebFont. This will work on all platforms.

fontFamily: Utils.loadWebFont "Cookie"

You can optionally pass in a second argument to load a certain font weight. In the example project above I used this to load the thinnest weight of Lato.

fontFamily: Utils.loadWebFont "Lato", 100

A font will load when the Text Layer becomes visible, but to avoid the slight delay this may give, you can pre-load a font and store it in a variable …

latoThin = Utils.loadWebFont "Lato", 100

… and then use that variable to set the font family:

title = new TextLayer
fontFamily: latoThin

Loading other web fonts

Another utility, Utils.loadWebFontConfig, gives access to the Web Font Loader library. With it, you can load fonts not only from Google Fonts, but also from Typekit, Fonts.com, Fontdeck, and even self-hosted web fonts.

To load your own custom fonts, for instance, you would do something like this, as explained in the library’s docs:

Utils.loadWebFontConfig
custom:
families: [“Some awesome font”, “and another”]
urls: [“location/of/font-face/css-file.css”]

But the library can also be used to pre-load multiple Google fonts …

Utils.loadWebFontConfig
google:
families: ["Oswald", "Cookie"]

… which you can then use by referring to their name.

myText = new TextLayer
text: "Hello World"
fontFamily: "Oswald"

Embedding a font file in your project

You can include TrueType and OpenType font files in your project folder and load them with a few lines of CSS.

First, with insertCSS you insert an @font-face at-rule to load the font(s).

# Loading the TTF files in the /fonts/ folder
# and giving them a unique font family name
Utils.insertCSS """
@font-face {
font-family: "Walt";
src: url("fonts/New Walt Disney.ttf");
}
@font-face {
font-family: "Walt UI";
src: url("fonts/New Walt Disney UI.ttf");
}
"""

You can then use the names you picked to set a Text Layer’s font family:

textLayerA.fontFamily = "Walt"textLayerB.fontFamily = "Walt UI"
👀 view in browser — 🖥 open in Framer

10. Font Weight

In Code, you set the different weights with numbers, just as in CSS.

Here’s a list of what the different values stand for:

  • 100 — Thin / Hairline
  • 200 — Extra Light / Ultra Light
  • 300 — Light
  • 400 — Normal (the default)
  • 500 — Medium
  • 600 — Semi Bold / Demi Bold
  • 700 — Bold
  • 800 — Extra Bold / Ultra Bold
  • 900 — Black / Heavy

Instead of 400 you can also write "normal”, and when typing "bold” you’ll get the 700 weight.

In Design, you can see which font weights a specific typeface actually has (and select them from the list).

Very few typefaces will have all these weights, though. Most only have Normal and Bold.

When a typeface doesn’t have the weight that you picked, Framer will use the closest available one. (So it makes sense to check in Design if a weight even exists.)

Sometimes a particular weight might be found in a separate typeface. To get the black version of "Arial", for instance, you’ll need to use the "Arial Black" font family.

Note: Even though fontWeight is a numeric value, it is not animatable. Animating to a new value will simply skip the in-between values.

11. Font Style

Italic and Oblique are the options here, but you could pick either one.

Well, in theory there should be a difference …

  • An italic is a specially drawn, more cursive version of a typeface.
  • And an oblique is simply a slanted version of the typeface.
Garamond / Garamond Italic / Garamond Oblique (from Wikipedia)

… but in practice only a few fonts have both versions. (Lucida Grande seems to be one, but that’s not a web font.)

When there’s no italic version available, oblique will be used anyway (or created on the fly). That’s why I always pick "italic", so that when a font might have both I’ll at least get the attractive option.

The ‘Times’ typeface, at the top, has an italic version, but the (iOS default) ‘San Francisco’ at the bottom does not have one.

  • Framer docs: text.fontStyle
  • Italic can be ✅ set in Framer Design in the weight menu (when a typeface has it)

12. Line Height

The lineHeight property is not a points (or pixels) value, but a multiplier of fontSize.

By default, it’s 1.25 (in Code): one and a quarter times the font size. So with a font size of 40, the distance between two lines will be 50 points. (Although this currently seems to be off for small values.)

Pro tip: When you have only one line of text you can use line height to define the amount of vertical space around the text, for instance when making a button (see the example in Background Color above).

  • Framer docs: text.lineHeight
  • Can be ✅ set in Framer Design (but with only 1 decimal: 1.2, 1.3 etc)
  • Can be ✅ animated

13. Font

With .font you can set a bunch of properties at once, in one single line.

These are the possible properties, in their correct order:

"fontStyle fontWeight fontSize/lineHeight fontFamily"

But only two are required: fontSize and fontFamily.

textA = new TextLayer
font: "32px -apple-system"

(Yes, you do write px for ‘pixels’, but, as with any fontSize value in Framer, the value is actually in ‘points’.)

The remaining properties are optional. Here’s an example with all possible properties:

textA = new TextLayer
font: "italic 400 25px/1.5 Menlo"

(Don’t forget to type a / before the line height.)

14. Text Align

The alignment of the text inside the Text Layer block.

Next to the CSS values "left”, "right”, and "center” you can also use Framer’s Align functions.

15. Shadow Color

Setting this property on a standard layer would give the layer itself a shadow, but on a Text Layer, it affects the text.

Don’t forget to also set shadowX and/or shadowY to actually see a shadow appear.

16. Shadow X

A shadow is really just a copy of the text placed underneath the text at a certain distance. Shadow X sets this distance to the right, or to the left when you use a negative value.

The distance is in points, but halves (e.g., 4.5) can be used to add a pixel (on a @2x device).

  • Framer docs: text.shadowX
  • Can be ✅ set in Framer Design
  • Can be ✅ animated

17. Shadow Y

The same as Shadow X, but for the vertical axis. A positive number will move the shadow that many points downwards, and a negative value will produce a shadow from the top edge.

The distance is in points, but halves (e.g., 4.5) can be used to add a pixel (on a @2x device).

  • Framer docs: text.shadowY
  • Can be ✅ set in Framer Design
  • Can be ✅ animated

18. Shadow Blur

The default value is 0, which will produce a sharp ‘high noon’ shadow. Give it a higher number to soften the shadow with a Gaussian blur.

  • Framer docs: text.shadowBlur
  • Can be ✅ set in Framer Design
  • Can be ✅ animated

19. Letter Spacing

This property adds spacing between the letters of the text.

For example, when set to 3 it will add three points of additional spacing between every two letters (and will also add six points to every space).

Negative values will subtract this many points from the normal spacing.

Do you want to kern between letters? You can in Design. Select two letters to adjust the Letter Spacing between them.

20. Word Spacing

This property adds extra space to every … space.

So changing it to 10, like in the prototype below, will add ten points of distance between any two words.

21. Text Transform

A quick way to make text all caps, or no caps at all, or turn the text into a title by capitalizing all the words.

22. Text Decoration

For creating underline, overline, or strike-through text.

You can use combinations, so, for example, adding an underline and an overline (if you must) is possible:

textDecoration: "underline overline"

23. Text Indent

The textIndent property sets the indentation of the first line of text.

It’s in points, and you can use a negative value to move the line to the left.

24. Direction

By default your text will run from ‘left to right’, just like the text you’re reading right now. So you’ll only change this property when working with Arabic, Hebrew, or other right-to-left languages.

Notice how switching to "right-to-left" places the period at the correct end of the Arabic and Hebrew sentences.

(The prototype also changes textAlign.)

25. Setting other CSS properties

You can set most other CSS properties on a Text Layer (or any other layer), but you’ll have to add them to the style property.

(You can type most of them in camelCase; here’s a page on MDN with an overview.)

In this example, I gave the layer a gradient background (by setting background instead of backgroundColor) and then used a webkit-specific property to clip (mask) that background with the text.

# Linear gradient: shades of gray
textLayerA.style =
background: "linear-gradient(#eee, #333)"
webkitBackgroundClip: "text"

For this to work we also have to remove the color of the text by setting it to "transparent" or null:

textLayerA.color = null

The other three examples are the same, only with different gradient settings.

# Linear gradient: starts at 30% of the height and stops at 90%
background: "linear-gradient(rgb(98,125,77) 30%, rgb(31,59,8) 90%)"
# Linear gradient: all the colors!
background: "linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet)"
# Radial gradient: from yellow in top right corner to orange
background: "radial-gradient(circle at top right, yellow, #f06d06)"

I hope you 👏 liked this overview.

And if you did, check out my book — it has all the details about Framer Code, tutorials, and hundreds of example projects (276 Framer projects to be exact). And there’s a free preview version!

The Framer book

--

--