How to wrap text in Python

Learn how to wrap text in Python. Discover different methods, tips, real-world applications, and how to debug common errors.

How to wrap text in Python
Published on: 
Mon
Apr 6, 2026
Updated on: 
Wed
Apr 8, 2026
The Replit Team

Wrapping text in Python is a fundamental skill for clean, readable output in applications. It allows you to constrain long strings to a specific width, which improves the user experience.

In this article, you’ll explore techniques to wrap text, including Python's textwrap module. You'll also find practical tips, real-world applications, and debugging advice for your projects.

Basic text wrapping with textwrap.fill()

import textwrap
text = "This is a long string that needs to be wrapped to fit within a specific width."
wrapped_text = textwrap.fill(text, width=30)
print(wrapped_text)--OUTPUT--This is a long string that
needs to be wrapped to fit
within a specific width.

The textwrap.fill() function offers the most direct way to wrap a paragraph. It takes your string and returns a new string with line breaks inserted, ensuring no line exceeds the specified width.

In this case, width=30 instructs the function to wrap the text at or before the 30th character. The module intelligently breaks lines at word boundaries, which prevents awkward splits in the middle of words and keeps the output readable.

Standard text wrapping techniques

While textwrap.fill() is great for simple cases, the module offers more granular control with functions like textwrap.wrap(), textwrap.indent(), and textwrap.dedent().

Using textwrap.wrap() to get a list of lines

import textwrap
text = "Python provides simple ways to wrap text with the textwrap module."
wrapped_lines = textwrap.wrap(text, width=25)
for line in wrapped_lines:
print(f"Line: {line}")--OUTPUT--Line: Python provides simple
Line: ways to wrap text with the
Line: textwrap module.

Unlike textwrap.fill(), the textwrap.wrap() function returns a list of strings. It’s a great choice when you need more control over the output, as you can process each line individually before displaying it.

  • This approach lets you add prefixes to each line, store them for later use, or perform other manipulations. The function still breaks lines at word boundaries to maintain readability, just like textwrap.fill().

Controlling indentation with textwrap.indent()

import textwrap
text = "First line.\nSecond line.\nThird line."
indented_text = textwrap.indent(text, prefix=" ")
print(indented_text)--OUTPUT--First line.
Second line.
Third line.

The textwrap.indent() function lets you add a common prefix to lines of text. You control what gets added using the prefix argument. Notice how it only indents lines after the first one by default—this is useful for formatting paragraphs where the first line remains flush with the margin.

  • If you need to indent every line, you can add a predicate argument. For example, predicate=lambda line: True tells the function to apply the prefix to all lines without exception.

Working with multi-line text using textwrap.dedent()

import textwrap
text = """
This text has inconsistent
indentation that we
want to normalize.
"""
dedented_text = textwrap.dedent(text)
print(dedented_text)--OUTPUT--This text has inconsistent
indentation that we
want to normalize.

The textwrap.dedent() function is your tool for cleaning up multi-line strings. It inspects the text and removes any common leading whitespace from each line. This is especially handy for triple-quoted strings that are indented to match your code's structure, making the output clean and uniform.

  • It intelligently finds the minimum indentation across all lines and strips that amount from the start of every line. This normalizes the block while preserving any relative indentation within it, as seen in the example.

Advanced text wrapping techniques

Beyond the standard functions, the textwrap module offers powerful tools for creating custom wrappers, truncating text, and dynamically adjusting to terminal widths.

Creating custom wrappers with the TextWrapper class

import textwrap
wrapper = textwrap.TextWrapper(width=40, initial_indent="* ", subsequent_indent=" ")
text = "This example shows how to use a TextWrapper object for more control over text formatting."
wrapped_text = wrapper.fill(text)
print(wrapped_text)--OUTPUT--* This example shows how to use a
TextWrapper object for more control over
text formatting.

For more complex formatting, you can create a reusable TextWrapper object. This approach is more efficient than repeatedly passing arguments to functions like textwrap.fill() because you configure the wrapping options once and apply them to multiple strings.

  • The initial_indent argument adds a prefix to the very first line.
  • subsequent_indent applies a prefix to all following lines, which is great for creating hanging indents.

This lets you easily create custom layouts, like the bulleted-list style shown in the example.

Truncating text with textwrap.shorten()

import textwrap
long_text = "This is a very long text that we want to truncate to a shorter length."
shortened = textwrap.shorten(long_text, width=30, placeholder="...")
print(shortened)--OUTPUT--This is a very long text...

The textwrap.shorten() function is perfect for creating summaries or previews. It truncates a string to fit within a specified width and adds a placeholder at the end.

  • The width argument sets the maximum length of the final string, including the placeholder itself.
  • You can customize the trailing text with the placeholder argument. In the example, it’s set to ....

The function attempts to cut the text at the last complete word, which keeps the result as readable as possible.

Adapting to terminal width dynamically

import textwrap
import shutil
import os
text = "This text will be wrapped according to your current terminal width."
terminal_width = shutil.get_terminal_size((80, 20)).columns
wrapped = textwrap.fill(text, width=terminal_width - 5)
print(wrapped)--OUTPUT--This text will be wrapped according to your current terminal width.

For command-line applications, you can create a more polished user experience by wrapping text to fit the user's terminal. The shutil module makes this straightforward, allowing your program's output to adjust dynamically to different screen sizes.

  • The shutil.get_terminal_size() function retrieves the terminal's current width and height. You can grab just the width using its .columns attribute.
  • By setting the width in textwrap.fill() to a value like terminal_width - 5, you create a small margin. This prevents text from running up against the edge of the window, making it much easier to read.

Move faster with Replit

Replit is an AI-powered development platform where Python dependencies are pre-installed, so you can skip setup and start coding instantly. Describe what you want to build, and Agent 4 handles everything—from writing the code and connecting APIs to deploying it live.

Instead of piecing together techniques, you can describe the app you actually want to build and Agent will take it from idea to working product:

  • A command-line utility that takes raw text and formats it into clean, indented paragraphs using functions like textwrap.indent().
  • A web app that generates content previews by truncating articles with textwrap.shorten() and adding a custom placeholder.
  • A dashboard widget that dynamically wraps long user comments to fit a fixed-width display.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

Even with a simple module like textwrap, you can run into a few tricky situations that require a bit more attention.

Handling words longer than the specified width

By default, textwrap won’t break words that are longer than your specified width, which can lead to lines that overflow your layout. To fix this, you can set the break_long_words parameter to True in your TextWrapper object or wrapping function. This forces the module to split the oversized word to fit the width constraint.

  • Keep in mind that this can make text harder to read, so it’s best used when maintaining a strict width is more important than word integrity.

Preserving or replacing existing line breaks with textwrap

Another common issue is how textwrap handles existing line breaks. By default, it replaces all whitespace characters, including newlines, with single spaces. This means it will merge separate paragraphs into one large block of text before wrapping.

  • To preserve your paragraphs, you can set replace_whitespace=False. When you do this, the wrapper will treat existing line breaks as paragraph separators and wrap each one independently.

Understanding initial_indent vs subsequent_indent confusion

The distinction between initial_indent and subsequent_indent often causes confusion. It’s easy to assume they apply to each paragraph, but they operate on the entire text block as a whole.

  • initial_indent: This prefix is applied only once, to the very first line of the output.
  • subsequent_indent: This prefix is applied to all other wrapped lines that follow the first one.

If you need to indent each paragraph differently, you should split the text into paragraphs first and then apply wrapping to each one individually.

Handling words longer than the specified width

A common challenge you'll face is handling words that exceed your specified width. By default, textwrap prioritizes word integrity and won't split them, causing lines to overflow and break your layout. See what happens in the code below.

import textwrap
text = "This text contains a supercalifragilisticexpialidocious word that exceeds the width."
wrapped = textwrap.fill(text, width=20)
print(wrapped)

The long word supercalifragilisticexpialidocious is longer than the width of 20. Since textwrap won't split the word by default, the line overflows your layout. The code below shows how to handle this situation.

import textwrap
text = "This text contains a supercalifragilisticexpialidocious word that exceeds the width."
wrapper = textwrap.TextWrapper(width=20, break_long_words=True)
wrapped = wrapper.fill(text)
print(wrapped)

To fix overflowing lines, create a TextWrapper object and set its break_long_words parameter to True. This forces the wrapper to split any word that's longer than the specified width, ensuring your layout remains intact.

This approach is best when maintaining a strict column width is more critical than preserving whole words, such as in command-line interfaces or formatted reports. Just be aware that it can make the text harder to read.

Preserving or replacing existing line breaks with textwrap

By default, textwrap functions replace all whitespace characters, including newlines, with single spaces. This can unintentionally merge distinct paragraphs into one large block of text. The code below shows how this behavior can affect your output when using textwrap.fill().

import textwrap
text = "First paragraph.\n\nSecond paragraph with\na line break."
wrapped = textwrap.fill(text, width=30)
print(wrapped)

The function merges the two paragraphs because it replaces all whitespace, including newlines, with single spaces. The code below shows how to prevent this and wrap each paragraph independently while maintaining the original line breaks.

import textwrap
text = "First paragraph.\n\nSecond paragraph with\na line break."
paragraphs = text.split('\n\n')
wrapped_paragraphs = [textwrap.fill(p.replace('\n', ' '), width=30) for p in paragraphs]
result = '\n\n'.join(wrapped_paragraphs)
print(result)

To keep your paragraphs separate, you need to process them individually. The solution involves splitting the text into a list of paragraphs using text.split('\n\n'). You can then loop through this list, apply textwrap.fill() to each paragraph, and join them back together with double newlines. This approach gives you precise control over wrapping while respecting the original structure of your text, which is especially useful when formatting user-generated content or imported text files.

Understanding initial_indent vs subsequent_indent confusion

It's easy to get tripped up by the difference between initial_indent and subsequent_indent. These arguments don't apply to each paragraph but to the entire text block as one unit, which can cause formatting surprises. The following code shows what happens.

import textwrap
text = "This is a long paragraph that demonstrates how indentation works with the textwrap module."
wrapped = textwrap.fill(text, width=30, initial_indent=" ")
print(wrapped)

The code only indents the first line because initial_indent applies just once to the entire text block, leaving the rest untouched. The example below shows how to get the formatting you likely intended.

import textwrap
text = "This is a long paragraph that demonstrates how indentation works with the textwrap module."
wrapped = textwrap.fill(text, width=30, initial_indent=" ", subsequent_indent=" ")
print(wrapped)

To indent the entire paragraph, you must use both initial_indent and subsequent_indent together. The initial_indent argument applies a prefix only to the first line of the wrapped text, while subsequent_indent handles all following lines. Using them in combination ensures every line is indented uniformly. It's a common pattern for formatting text blocks in reports or command-line outputs where consistent alignment is key to readability.

Real-world applications

Beyond troubleshooting common errors, text wrapping is fundamental for building clean, user-friendly command-line applications.

Formatting help text for CLI applications with textwrap

The textwrap module is perfect for creating the kind of clean, readable help text that makes a command-line tool feel polished and user-friendly.

import textwrap

def format_command_help():
command_desc = "Converts files between different formats (JSON, CSV, XML, YAML)"
usage = "convert.py [options] input_file output_file"

print("FILE CONVERTER UTILITY")
print("\nDESCRIPTION:")
print(textwrap.fill(command_desc, width=50, initial_indent=" ",
subsequent_indent=" "))
print("\nUSAGE:")
print(textwrap.indent(usage, " "))

format_command_help()

This function, format_command_help, shows how to structure help text for a command-line tool. It combines two different textwrap functions to achieve a clean layout.

  • The textwrap.fill() function is used on the description. By setting both initial_indent and subsequent_indent, it ensures the entire paragraph is wrapped and indented uniformly.
  • In contrast, textwrap.indent() is applied to the usage string, which indents the line without wrapping it. This is ideal for short, single-line instructions.

Creating a text-based menu with proper formatting

You can also use a TextWrapper object to create clean, readable menus by wrapping the descriptions for each option to a consistent width.

import textwrap

def display_menu(title, options):
# Print title
print(f"\n{title}\n" + "-" * len(title))

# Create a text wrapper for option descriptions
wrapper = textwrap.TextWrapper(
width=50,
initial_indent=" ",
subsequent_indent=" "
)

# Print each option with wrapped description
for idx, (option, description) in enumerate(options, 1):
print(f"{idx}. {option}")
print(wrapper.fill(description))
print()

menu_options = [
("Export Data", "Export the current dataset to CSV or JSON format."),
("Import Data", "Import data from external sources including databases and files."),
("Exit", "Close the application")
]

display_menu("DATA MANAGEMENT MENU", menu_options)

This code shows an efficient pattern for applying consistent text formatting. The display_menu function avoids repetitive code by creating a single TextWrapper object upfront with all the formatting rules, like width and indentation, stored in one place.

  • As the function loops through the options, it simply calls wrapper.fill() on each description to apply the style.
  • This approach separates the formatting logic from the loop’s main task, which makes the code cleaner and easier to modify if you need to change the menu’s layout later.

Get started with Replit

Now, turn these techniques into a real tool. Tell Replit Agent to "build a CLI that formats help text" or "create a script that generates truncated content previews for a dashboard."

Replit Agent writes the code, tests for errors, and deploys your application. It handles the entire development cycle for you. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.