Ship internal tools in hours, not weeks. Real auth, users, jobs, audit logs, and cohesive UI included. Early access $249 $499 → [Get it now]

How to repeat a string multiple times in JavaScript

Repeating strings multiple times is useful for creating patterns, generating padding, building visual separators, and implementing features like progress indicators or formatted output in JavaScript applications. With over 25 years of experience in software development and as the creator of CoreUI, I’ve implemented string repetition in components like loading animations, table formatting, progress bars, and text decorations where repeated patterns enhance visual presentation and functionality. From my extensive expertise, the most modern and efficient solution is using the ES6 repeat() method, which provides clean syntax for string duplication. This approach is straightforward, performant, and specifically designed for creating repeated string patterns.

Use the repeat() method to duplicate a string a specified number of times.

const pattern = '*'
const repeated = pattern.repeat(5)
// Result: '*****'

The repeat() method creates a new string by concatenating the original string the specified number of times. In this example, '*'.repeat(5) produces '*****' by repeating the asterisk character 5 times. The method accepts a non-negative integer and returns an empty string if the count is 0. If you pass a decimal number, it will be truncated to an integer. The method throws a RangeError if the count is negative or if the result would exceed JavaScript’s maximum string length.

1. Edge Cases and Error Handling

Understanding how repeat() handles unusual inputs prevents runtime errors and unexpected behavior in production code.

// Zero repeats returns an empty string
console.log('hello'.repeat(0))
// Result: ''

// Decimal values are truncated (floored)
console.log('ab'.repeat(3.7))
// Result: 'ababab' (3, not 4)

// Negative count throws RangeError
try {
  'hello'.repeat(-1)
} catch (error) {
  console.log(error.message)
  // Result: 'Invalid count value: -1'
}

// Infinity also throws RangeError
try {
  'x'.repeat(Infinity)
} catch (error) {
  console.log(error.message)
  // Result: 'Invalid count value: Infinity'
}

// NaN is treated as 0
console.log('hello'.repeat(NaN))
// Result: ''

// Safe repeat wrapper for dynamic values
const safeRepeat = (str, count) => {
  if (!str || count == null) return ''
  const n = Math.floor(Number(count))
  if (!Number.isFinite(n) || n < 0) return ''
  return str.repeat(n)
}

console.log(safeRepeat('x', -5))        // ''
console.log(safeRepeat('x', '3'))       // 'xxx'
console.log(safeRepeat('x', undefined)) // ''
console.log(safeRepeat(null, 3))        // ''

The safeRepeat wrapper is useful when the repeat count comes from user input or API data where the value might not be a valid non-negative integer. For more on checking string values, see how to check if a string is empty in JavaScript.

2. String Padding with padStart() and padEnd()

For padding strings to a specific length, padStart() and padEnd() are more appropriate than manual repeat() calls. They handle the length calculation automatically.

// Left-pad a number with zeros
const orderNum = '42'
console.log(orderNum.padStart(6, '0'))
// Result: '000042'

// Right-pad for aligned output
const items = [
  { name: 'Widget', price: 9.99 },
  { name: 'Gadget', price: 149.50 },
  { name: 'Thingamajig', price: 24.00 }
]

items.forEach(item => {
  const padded = item.name.padEnd(15, '.')
  console.log(`${padded} $${item.price.toFixed(2)}`)
})
// Widget......... $9.99
// Gadget......... $149.50
// Thingamajig.... $24.00

// Compare: repeat() requires manual calculation
const manualPad = (str, targetLength, char = ' ') => {
  const padding = Math.max(0, targetLength - str.length)
  return str + char.repeat(padding)
}

// padEnd is cleaner
console.log('hello'.padEnd(10, '-'))
// Result: 'hello-----'

// Pad with multi-character strings
console.log('1'.padStart(8, '0x'))
// Result: '0x0x0x01' (pattern repeats and truncates)

Use padStart() for left-padding (numbers, IDs, timestamps) and padEnd() for right-padding (aligned tables, fixed-width formatting). Both are ES2017 features supported in all modern browsers.

3. Building Visual Patterns and Separators

The repeat() method excels at creating visual elements for console output, text-based UI, and formatted strings.

// Horizontal separator
const separator = '─'.repeat(40)
console.log(separator)
// Result: '────────────────────────────────────────'

// Box drawing
const boxTop = '┌' + '─'.repeat(30) + '┐'
const boxBot = '└' + '─'.repeat(30) + '┘'
const boxLine = (text) => {
  const padding = 30 - text.length
  const left = Math.floor(padding / 2)
  const right = padding - left
  return '│' + ' '.repeat(left) + text + ' '.repeat(right) + '│'
}

console.log(boxTop)
console.log(boxLine('Hello World'))
console.log(boxBot)
// ┌──────────────────────────────┐
// │         Hello World          │
// └──────────────────────────────┘

// Tree-style indentation
const tree = [
  { name: 'src', depth: 0 },
  { name: 'components', depth: 1 },
  { name: 'Button.tsx', depth: 2 },
  { name: 'Card.tsx', depth: 2 },
  { name: 'utils', depth: 1 },
  { name: 'helpers.ts', depth: 2 }
]

tree.forEach(item => {
  const indent = '  '.repeat(item.depth)
  const prefix = item.depth > 0 ? '├── ' : ''
  console.log(indent + prefix + item.name)
})
// src
//   ├── components
//     ├── Button.tsx
//     ├── Card.tsx
//   ├── utils
//     ├── helpers.ts

String repetition is the foundation for text-based formatting. The box-drawing example demonstrates combining repeat() with string length calculations for centered text — a pattern useful for CLI tools and formatted log output.

4. Building Progress Bars and Indicators

Creating text-based progress bars is a classic use case for repeat(), useful in CLI tools, log messages, and simple UI indicators.

// Text-based progress bar
const progressBar = (percent, width = 30) => {
  const filled = Math.round(width * percent / 100)
  const empty = width - filled
  const bar = '█'.repeat(filled) + '░'.repeat(empty)
  return `[${bar}] ${percent}%`
}

console.log(progressBar(0))
// [░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%

console.log(progressBar(45))
// [██████████████░░░░░░░░░░░░░░░░░░] 45%

console.log(progressBar(100))
// [██████████████████████████████] 100%

// Star rating display
const starRating = (rating, max = 5) => {
  const full = Math.floor(rating)
  const empty = max - full
  return '★'.repeat(full) + '☆'.repeat(empty)
}

console.log(starRating(3))    // ★★★☆☆
console.log(starRating(5))    // ★★★★★
console.log(starRating(0))    // ☆☆☆☆☆

// Loading spinner frames
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']

// Dot-based loading indicator
const loadingDots = (frame, maxDots = 3) => {
  const dots = (frame % (maxDots + 1))
  return 'Loading' + '.'.repeat(dots) + ' '.repeat(maxDots - dots)
}

console.log(loadingDots(0))  // 'Loading   '
console.log(loadingDots(1))  // 'Loading.  '
console.log(loadingDots(2))  // 'Loading.. '
console.log(loadingDots(3))  // 'Loading...'

These patterns appear in CLI tools and admin dashboards. The progress bar function is commonly used in CoreUI React components to render text-based alternatives alongside graphical progress indicators.

5. Generating Test Data and Placeholder Content

Repeating strings is invaluable for creating test fixtures, placeholder content, and boundary-testing scenarios.

// Generate placeholder text of specific length
const placeholder = (length) => {
  const base = 'Lorem ipsum dolor sit amet. '
  const repeated = base.repeat(Math.ceil(length / base.length))
  return repeated.slice(0, length)
}

console.log(placeholder(50))
// Result: 'Lorem ipsum dolor sit amet. Lorem ipsum dolor sit '

// Generate test strings for boundary testing
const testCases = [
  { name: 'empty', value: '' },
  { name: 'single char', value: 'a' },
  { name: '255 chars', value: 'x'.repeat(255) },
  { name: '256 chars', value: 'x'.repeat(256) },
  { name: '1000 chars', value: 'x'.repeat(1000) }
]

testCases.forEach(({ name, value }) => {
  console.log(`${name}: length=${value.length}`)
})

// CSV row generator for testing
const generateCSVRow = (columns, rowIndex) => {
  return columns
    .map((col, i) => `${col}_${rowIndex}`)
    .join(',')
}

const headers = ['name', 'email', 'role']
const csvRows = [
  headers.join(','),
  ...Array.from({ length: 5 }, (_, i) => generateCSVRow(headers, i + 1))
]
console.log(csvRows.join('\n'))
// name,email,role
// name_1,email_1,role_1
// name_2,email_2,role_2
// ...

// Create indentation strings for code formatters
const indent = (level, size = 2) => ' '.repeat(level * size)

console.log(indent(0) + 'function hello() {')
console.log(indent(1) + 'const msg = "hi"')
console.log(indent(1) + 'return msg')
console.log(indent(0) + '}')

Generating test data with repeat() is far more readable than manually typing long strings. The boundary test pattern helps verify that string length limits are enforced correctly in CoreUI form components with maxLength validation.

6. Combining repeat() with Template Literals

Template literals and repeat() together enable dynamic, readable string construction for HTML generation, formatted output, and structured content.

// Generate HTML list items
const createList = (items) => {
  const indent = '  '
  const listItems = items
    .map(item => `${indent}<li>${item}</li>`)
    .join('\n')
  return `<ul>\n${listItems}\n</ul>`
}

console.log(createList(['React', 'Angular', 'Vue']))
// <ul>
//   <li>React</li>
//   <li>Angular</li>
//   <li>Vue</li>
// </ul>

// Generate a multiplication table
const multiTable = (size) => {
  const header = '   │' + Array.from({ length: size }, (_, i) =>
    String(i + 1).padStart(4)
  ).join('')
  const divider = '───┼' + '────'.repeat(size)

  const rows = Array.from({ length: size }, (_, i) => {
    const row = Array.from({ length: size }, (_, j) =>
      String((i + 1) * (j + 1)).padStart(4)
    ).join('')
    return `${String(i + 1).padStart(3)}${row}`
  })

  return [header, divider, ...rows].join('\n')
}

console.log(multiTable(4))
//    │   1   2   3   4
// ───┼────────────────
//   1│   1   2   3   4
//   2│   2   4   6   8
//   3│   3   6   9  12
//   4│   4   8  12  16

// Dynamic heading underlines
const heading = (text, char = '=') => {
  return `${text}\n${char.repeat(text.length)}`
}

console.log(heading('Chapter 1'))
// Chapter 1
// =========

console.log(heading('Section A', '-'))
// Section A
// ---------

Combining repeat() with padStart() and template literals creates clean, maintainable string formatting code. For more on building strings from arrays, see how to convert an array to a string in JavaScript.

Best Practice Note:

This is the same approach we use in CoreUI React components for creating visual separators, padding strings, and generating repeated UI patterns across our component library. Use repeat() for simple duplication, padStart()/padEnd() for padding to a target length, and template literals for complex formatted output. Guard against invalid repeat counts when the value comes from user input — negative numbers and Infinity throw RangeError. For trimming the opposite direction, see how to trim whitespace from a string in JavaScript.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team