Skip to main content

String Formatting

replaceLineBreak

Replace line breaks with HTML <br /> tags.
function replaceLineBreak(content?: string): string
content
string
String with line breaks
import { replaceLineBreak } from '@proton/shared/lib/helpers/string';

const text = 'Line 1\nLine 2\r\nLine 3';
const html = replaceLineBreak(text);
// 'Line 1<br />Line 2<br />Line 3'

toCRLF

Convert line breaks to CRLF (\r\n) format.
function toCRLF(str: string): string
import { toCRLF } from '@proton/shared/lib/helpers/string';

const unix = 'Line 1\nLine 2\nLine 3';
const windows = toCRLF(unix);
// 'Line 1\r\nLine 2\r\nLine 3'

addPlus

Format an array by showing the first item and a count of remaining items.
function addPlus(items?: string[]): string
items
string[]
Array of strings to format
import { addPlus } from '@proton/shared/lib/helpers/string';

addPlus(['Alice']);
// 'Alice'

addPlus(['Alice', 'Bob', 'Charlie']);
// 'Alice, +2'

addPlus([]);
// ''

stripLeadingSlash / stripTrailingSlash

Remove leading or trailing slashes from strings.
function stripLeadingSlash(str: string): string
function stripTrailingSlash(str: string): string
function stripLeadingAndTrailingSlash(str: string): string
import { stripLeadingSlash } from '@proton/shared/lib/helpers/string';

stripLeadingSlash('/path/to/file');
// 'path/to/file'

stripLeadingSlash('///multiple');
// 'multiple'

removeDiacritics

Remove diacritical marks from characters.
function removeDiacritics(str: string): string
import { removeDiacritics } from '@proton/shared/lib/helpers/string';

removeDiacritics('Café');
// 'Cafe'

removeDiacritics('Naïve');
// 'Naive'

removeDiacritics('Zürich');
// 'Zurich'

truncatePossiblyQuotedString

Truncate a string that may be wrapped in quotes.
function truncatePossiblyQuotedString(
  string: string,
  charsToDisplay: number
): string
string
string
required
String to truncate (may be quoted)
charsToDisplay
number
required
Maximum characters to display
import { truncatePossiblyQuotedString } from '@proton/shared/lib/helpers/string';

truncatePossiblyQuotedString('"Long filename.pdf"', 15);
// '"Long fil…e.pdf"'

truncatePossiblyQuotedString('Regular filename.pdf', 15);
// 'Regular…me.pdf'

Hash Utilities

getHashCode

Compute a deterministic numeric hash for a string.
function getHashCode(str: string): number
str
string
required
String to hash
This is NOT a cryptographic hash function. Different strings may produce the same hash code.
import { getHashCode } from '@proton/shared/lib/helpers/string';

const hash1 = getHashCode('hello');
const hash2 = getHashCode('hello');
console.log(hash1 === hash2); // true (deterministic)

const hash3 = getHashCode('world');
console.log(hash1 === hash3); // false (different strings)

HTML Utilities

removeHTMLComments

Remove HTML comments from a string.
function removeHTMLComments(str: string): string
import { removeHTMLComments } from '@proton/shared/lib/helpers/string';

const html = '<div><!-- Comment -->Content</div>';
const clean = removeHTMLComments(html);
// '<div>Content</div>'

URL Formatting

buildMailTo

Build a mailto: URL from an email address.
function buildMailTo(email?: string): string
import { buildMailTo } from '@proton/shared/lib/helpers/email';

const mailtoUrl = buildMailTo('[email protected]');
// 'mailto:[email protected]'

<a href={mailtoUrl}>Email User</a>

getEmailTo

Extract email address from a mailto: URL or return the input string.
function getEmailTo(str: string, decode?: boolean): string
str
string
required
Mailto URL or email string
decode
boolean
default:"true"
Whether to decode URI components
import { getEmailTo } from '@proton/shared/lib/helpers/email';

getEmailTo('mailto:[email protected]');
// '[email protected]'

getEmailTo('[email protected]');
// '[email protected]'

getEmailTo('mailto:user%[email protected]', true);
// '[email protected]'

Practical Examples

Format Comment Display

import { replaceLineBreak, truncateMore } from '@proton/shared/lib/helpers/string';

function Comment({ text, maxLength }: { text: string; maxLength?: number }) {
  const displayText = maxLength
    ? truncateMore({ string: text, charsToDisplay: maxLength })
    : text;

  return (
    <div
      className="comment"
      dangerouslySetInnerHTML={{
        __html: replaceLineBreak(displayText)
      }}
    />
  );
}

Build Clean URL Paths

import {
  stripLeadingSlash,
  stripTrailingSlash
} from '@proton/shared/lib/helpers/string';

function buildApiUrl(baseUrl: string, endpoint: string): string {
  const cleanBase = stripTrailingSlash(baseUrl);
  const cleanEndpoint = stripLeadingSlash(endpoint);
  return `${cleanBase}/${cleanEndpoint}`;
}

buildApiUrl('https://api.example.com/', '/users/');
// 'https://api.example.com/users'

Search with Diacritics Insensitivity

import { removeDiacritics } from '@proton/shared/lib/helpers/string';

function searchItems(items: string[], query: string): string[] {
  const normalizedQuery = removeDiacritics(query.toLowerCase());

  return items.filter((item) => {
    const normalizedItem = removeDiacritics(item.toLowerCase());
    return normalizedItem.includes(normalizedQuery);
  });
}

const items = ['Café', 'Restaurant', 'Zürich'];
searchItems(items, 'Cafe'); // ['Café']
searchItems(items, 'Zurich'); // ['Zürich']

Generate Stable Avatar Colors

import { getHashCode, getInitials } from '@proton/shared/lib/helpers/string';

function UserAvatar({ name }: { name: string }) {
  const colors = [
    '#FF6B6B', '#4ECDC4', '#45B7D1',
    '#FFA07A', '#98D8C8', '#F7DC6F'
  ];

  const hash = Math.abs(getHashCode(name));
  const color = colors[hash % colors.length];
  const initials = getInitials(name);

  return (
    <div
      className="avatar"
      style={{ backgroundColor: color }}
    >
      {initials}
    </div>
  );
}

Format File Path Display

import { truncateMore, rtlSanitize } from '@proton/shared/lib/helpers/string';

function FilePath({ path }: { path: string }) {
  const safePath = rtlSanitize(path);
  const displayPath = truncateMore({
    string: safePath,
    charsToDisplayStart: 20,
    charsToDisplayEnd: 15
  });

  return <span className="file-path">{displayPath}</span>;
}

// Very long path shows as:
// "/very/long/path/t…/filename.ext"

Build docs developers (and LLMs) love