How to preserve newlines from Sanity text fields in HTML/React?

17 replies
Last updated: Mar 19, 2022
For example.. I have a
Text
field in Sanity on a document.. someone puts something like:
line one

line two
line three
That’s gonna come back as something like:

line one\n\nline two\nline three
But HTML/React don’t honor `\n`’s.. so the result looks like in the browser:

line oneline twoline three
Trying to figure out how to render these things so the new lines are retained during rendering..
AI Update

You're dealing with a common issue where plain text fields preserve newlines as \n characters, but HTML/React renders them as spaces. Here are your options:

Quick CSS Solution

The simplest approach is to use CSS white-space property:

<div style={{ whiteSpace: 'pre-wrap' }}>
  {yourTextField}
</div>

Or with a CSS class:

.preserve-newlines {
  white-space: pre-wrap;
}

This tells the browser to honor newline characters while still wrapping long lines normally.

JavaScript Solution

If you need more control, you can split on newlines and insert <br> tags:

{yourTextField.split('\n').map((line, i) => (
  <React.Fragment key={i}>
    {line}
    {i < yourTextField.split('\n').length - 1 && <br />}
  </React.Fragment>
))}

Better Long-term Solution: Use Portable Text

If you need any formatting beyond simple line breaks (bold, italic, links, etc.), consider using Sanity's Portable Text/block content field type instead of a plain text field. It's designed for this exact use case and gives you:

  • Proper paragraph and line break handling out of the box
  • Rich text formatting capabilities
  • Structured, portable content that renders consistently

Change your schema from:

{
  name: 'myField',
  type: 'text'
}

To:

{
  name: 'myField',
  type: 'array',
  of: [{type: 'block'}]
}

Then render it with a Portable Text component for your framework (React, Vue, Svelte, etc.).

But if you're sticking with plain text fields and just need newlines preserved, the white-space: pre-wrap CSS solution is your best bet!

Show original thread
17 replies
have you tried breaks and horizontal rules for this? Or creating a new paragraph?
instead of a text field, you may be better served with rich text via portabletext or markdown. Both work very well in the studio.
I tried to wrap my mind around getting the Portable Text field stuff.. spent a few hours trying.. Then I just gave up.. seems very overly complicated IMHO (I’ve been doing software engineering for 15+ years, so I don’t think I’m speaking from position of ignorance here).
In comparison to other CMS PaaS, just required way too much effort to make it worth it to me…

For Example.. Contentful.. you tell it, “I want a ‘Rich text’ field here” and it gives the user a CMS user a RT interface.. But then on the other side of their API, you just get markdown (which is really simple to render out)…
I tried to wrap my mind around getting the Portable Text field stuff.. spent a few hours trying.. Then I just gave up.. seems very overly complicated IMHO (I’ve been doing software engineering for 15+ years, so I don’t think I’m speaking from position of ignorance here).
In comparison to other CMS PaaS, just required way too much effort to make it worth it to me…

For Example.. Contentful.. you tell it, “I want a ‘Rich text’ field here” and it gives the user a CMS user a RT interface.. But then on the other side of their API, you just get markdown (which is really simple to render out)…
In the end I just used CSS to deal w/ the line-breaks since there’s no real requirement in feature I’m working on that needs RT, just needed to render the linebreaks properly: https://sanity-io-land.slack.com/archives/C01T1B5GVEG/p1647651918772749
The portabletext element is just a big json object with customizable definitions for each block and style. It also has interpreters built in for pasting from other rich text sources (pdf, word/gdocs, web sites, etc). Contentful has a very similar object behind the scenes as well in their rich text, as does notion and most others. Where it has an advantage in the studio from my experience is building custom nested components directly from other documents and content in your project…or create your own methods for nesting media or iframes or whatever else you want right from the ui. This makes media interactions and queries much easier within the sanity studio.
You can also fine tune the available markup more easily than others I’ve tried for not-as-technical publishers to use. Markdown is more readable and easier to just export to a single sheet of text. Text fields are just a single block that’s going to be treated the unless you’re writing your own element tags directly into it and then interpreting them later.

You can also create your own custom input element completely to nest and render how you want in the studio if you have the experience doing so, fork and tweak one of the official plugins, or whatever you want.
it is also possible to interpret portable text as markdown as well once imported
Yeah.. I have no doubt that’s it’s prolly a far more powerful data format.. I just found that it took too much to get it up and going, and like I said, didn’t really need it.. so instead I solved what I did need w/ 4 lines of CSS 😉
Yeah.. I have no doubt that’s it’s prolly a far more powerful data format.. I just found that it took too much to get it up and going, and like I said, didn’t really need it.. so instead I solved what I did need w/ 4 lines of CSS 😉
No worries. I use the heck out of markdown for personal projects myself, but if I’m building a platform for others to use I’m going to try to automate it with a nice rich text input that I can tweak, and for this portabletext does a really nice job without extra tooling if I’m already using sanity as a content source.
I’ve passed your feedback on and really appreciate it. Have fun and tinker with all of it as much or as little as you’d like. ^_^
I’ve passed your feedback on and really appreciate it. Have fun and tinker with all of it as much or as little as you’d like. ^_^
Thanks for that Julia!
Thanks for the feedback, and if you don’t mind
user Y
, I have a couple of questions:• Where was the friction specifically?
◦ Setting up the editor in the studio? Rendering it in the frontend? Both?
• What did you do to try to figure it out? Did you find any of the docs?
I found the docs.. I tried to implement in the studio as described and I ran into a hangup w/ the RT editor behaving erratically to inputs.
I found the docs.. I tried to implement in the studio as described and I ran into a hangup w/ the RT editor behaving erratically to inputs.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?