Do more. Type less. Colorize different.
coloredstrings is a small utility for expressive terminal colors and text styles. It exposes a fluent, chainable API for styling strings and can act as a drop-in replacement for similar packages like yachalk.
Designed to be suitable, useful, and "batteries-included".
Example:
import coloredstrings as cs
print(cs.bold.underline.red("Error:"), "Something went wrong.")
print(cs.blue.bold("Info:"), "Everything is OK")
print(cs.italic.green("Success!"))- No dependencies
- Composing styles in a chainable way:
black.on.white.bold("What's up?") - Nested colors and no nested styling bug
- Support for 16-color, 256-color, and 24-bit (truecolor / RGB / hex) modes
- Auto-detection of terminal color capabilities
- Automatically fallback to the nearest supported color if the requested color isn't supported
- Friendly autocomplete API
- Call any of named true colors as a method:
aqua,pinkand so on - Extend default styles with user-defined ones
- Strip ANSI escape codes with
strip_ansi - Friendly to CLI arguments:
--color&--no-color - Support for common envs:
FORCE_COLOR,NO_COLOR,CLICOLOR_FORCE&CLICOLOR - Curious how coloredstrings compares to other libraries? See Migrating from other libraries
Stable release from PyPI:
pip install coloredstringsLatest development version:
pip install git+https://github.com/samedit66/coloredstrings.gitRun the bundled demo:
python -m coloredstringsFeatures:
import coloredstrings as cs
print(cs.bold.underline.red("Error:"), "Something went wrong.")
print(cs.blue.bold("Info:"), "Everything is OK")
print(cs.italic.green("Success!"))
# styles accepts multiple arguments and a `sep` argument like `print`:
print(cs.green("That's", "great!"))
print(cs.blue(1, 3.14, True, sep=", "))
# Nesting and combining styles:
print(cs.red(f"Hello {cs.underline.on.blue('world')}!"))
print(
cs.green(
"I am a green line "
+ cs.blue.underline.bold("with a blue substring")
+ " that becomes green again!"
)
)
# 24-bit RGB / hex and 256-color:
print(cs.rgb(123, 45, 200)("custom"))
print(cs.rgb("#aabbcc")("hex is also supported"))
print(cs.rgb("purple")("as well as named colors too"))
print(cs.rgb((169, 169, 169))("tuples can also be used"))
print(cs.color256(37)("256-color example"))
# Define theme helpers:
error = cs.bold.red
warning = cs.rgb("#FFA500")
print(error("Error!"))
print(warning("Warning!"))
# Or extend with your own styles:
bootstrap = cs.extend(
primary="blue", # may be a color / style name
secondary=(169, 169, 169), # RGB-tuple color
success=cs.green, # or any `StyleBuilder` instance
)
print(bootstrap.primary("Click me!"))
print(bootstrap.italic.secondary("You can combine builtin styles with your own!"))
print(bootstrap.success("Complete."))Import coloredstrings module directly:
import coloredstrings as cs
print(cs.green.on.pink("green text on pink background"))Or use only needed styles:
from coloredstrings import white, red, blue
print(white.bold("white bold text"))
print(red("just red text"))
print(blue.strikethrough("blue strikethrough text"))Chainable API allows you to easily compose styles and use them. When passing final text to a style, you can pass multiple objects which will be turned to strings and joined using an optional sep argument (which defaults to a single space):
import coloredstrings as cs
print(cs.orange("text", 1, 1.0, True, sep="-"))Although you use cs everywhere, the actual work is done by an immutable StyleBuilder class under the hood. Because every style object is immutable, creating a new style from an existing one doesn't modify the original. This avoids accidental cross-contamination of styles present in yachalk:
from yachalk import chalk
import coloredstrings as cs
# With yachalk
s1 = chalk.italic
s2 = s1.red
print(s1("Chalk, am I red?"))
print(s2("Yes, you are!"))
print("-" * 8)
# With coloredstrings
s3 = cs.italic
s4 = s3.red
print(s3("Style, am I still red?"))
print(s4("Sure not, but I am!"))In this example, s1/s2 and s3/s4 behave differently: s1/s2 are actually the same style, while s3/s4 are truly independent styles.
coloredstrings — like yachalk and several other libraries — is built around chaining styles. Unlike some libraries, it does not provide separate background helpers such as bg_blue. Instead, use the on helper to mark that the next color in the chain should be a background color. This gives you explicit control over whether the color you add applies to the foreground or the background.
Example:
import coloredstrings as cs
# Red text on a blue background
print(cs.red.on.blue("Hey!"))
# Don't write code like this - it's hard to read!
# It's equivalent to `cs.white.on.black(...)` but much less clear
print(cs.white.on.on.black("Do not write code like that."))
# Green background with default foreground
print(cs.on.green("Text on a green background"))A few important gotchas:
-
If you chain multiple foreground colors, only the last foreground color takes effect:
print(cs.red.green.blue("Blue text")) # result: blue foreground
-
onaffects only the next color in the chain. For example:print(cs.on.magenta.cyan("Cyan text on magenta background"))
Here
magentabecomes the background (because ofon) andcyanis the foreground. -
Repeated calls to
onwithout an intervening color are redundant and hurt readability; prefer the simpler, clearer form.
coloredstrings tries its best to detect terminal color capabilities automatically (see coloredstrings.color_support.detect_color_support()), but detection can occasionally miss. You can explicitly set the color mode using the pseudo-style method color_mode(mode).
mode is a member of the coloredstrings.ColorMode enum with these values:
ColorMode.NO_COLORS- disable styling; no escape sequences are emittedColorMode.ANSI_16- 16 basic ANSI colorsColorMode.EXTENDED_256- 256 color modeColorMode.TRUE_COLOR- 24-bit RGB / truecolor support
Example:
from coloredstrings import style, ColorMode
# Notice `style`? It's a default style which does nothing.
# Force no colors
just_text = style.color_mode(ColorMode.NO_COLORS)
print(just_text.red("It isn't red"))
# Force truecolor
rgb_default = style.color_mode(ColorMode.TRUE_COLOR)
print(rgb_default.hex("#ca7e8d")("Hi!"))With a wide variety of options to force terminal color or not, coloredstrings respects common environment conventions (in order of precedence - higher precedence goes first):
-
FORCE_COLOR: if set, this variable can be used to force color output even when detection would otherwise disable it (for example, when output is being piped). Following values are supported:FORCE_COLOR<=0- same asColorMode.NO_COLORorNO_COLORenvironment variableFORCE_COLOR=1- same asColorMode.ANSI_16FORCE_COLOR=2- same asColorMode.EXTENDED_256FORCE_COLOR>=3- same asColorMode.TRUE_COLOR
-
NO_COLOR: if this environment variable is present (with any value other than an empty string), coloredstrings will avoid emitting color escape sequences. This is the community-standard way for users to opt out of colored output. -
CLICOLOR_FORCE: same asFORCE_COLOR. -
CLICOLOR: same asColorMode.ANSI_16.
You can still programmatically override detection by calling style.color_mode(...) as shown above.
Note
CLI arguments take precedence over any environment variable.
You can also specify command-line flags like --no-color to disable colors and --color to enable them.
Example with a file cool.py:
import coloredstrings as cs
print(cs.red(f"Hello {style.blue('world')}!"))# Run with python
python cool.py --no-color
# Run with uv
uv run cool.py --colorMany terminals do not support full truecolor (ColorMode.TRUE_COLOR). When a requested color cannot be represented in the current color mode, coloredstrings automatically maps the requested color into the best available color space and emits the closest supported color. In short: you will still get colored output, though the result may be an approximation of the original color.
reset- Reset the current style chain. Widely supported.bold- Make the text bold (increases weight). Widely supported.dim(aliases:faint,dark) - Render the text with lower intensity / brightness. Support varies.italic- Render text in italic. Support varies across terminals.underline- Draw a horizontal line below the text. Support varies.double_underline- Draw a double underline under the text. Not widely supported.overline- Draw a horizontal line above the text. Not widely supported.inverse(alias:reverse) - Swap foreground and background colors (invert colors).hidden(alias:concealed) - Do not display the text (it is still present in the output stream).strike(alias:strikethrough) - Draw a horizontal line through the center of the text. Support varies.blink(alias:slow_blink) - Make the text blink. Often unsupported in modern terminals; avoid depending on it.rapid_blink- Faster blink. Often unsupported in modern terminals; avoid depending on it.framed- Draw a frame around the text. Rarely supported.encircle(alias:circle) - Draw a circle/encircle the text. Rarely supported.visible- Show text only when a color mode is enabled (anything other thanColorMode.NO_COLOR). Mainly used for cosmetic things.
Note on attributes: Most attributes stack (they combine instead of overriding). Terminal support for many of these attributes is spotty - prefer basic attributes (
bold,underline,inverse) for portability.
blackredgreenyellowbluemagentacyanwhitebright_black(aliases:gray,grey)bright_redbright_greenbright_yellowbright_bluebright_magentabright_cyanbright_whitecolor256(index)- 256 colorrgb(r, g, b),rgb(hex),rgb(color_name)- 24-bit RGB color
When you call cs with a method not defined above, it tries to interpret the method name as a named color.
This allows having many color methods without the need to define them explicitly:
import coloredstrings as cs
from coloredstrings import purple
print(cs.lavender("`lavender` is not defined internally"))
print(purple("Neither is `purple`."))If you’ve used other Python color or formatting libraries before, coloredstrings will feel familiar but more robust and consistent. Below is a quick comparison of how it differs from popular alternatives:
- colorama provides low-level ANSI control and Windows compatibility but lacks a fluent API.
coloredstringssupports more colors, styles and requires no use of ANSI codes directly.- Example:
# colorama from colorama import Fore, Style print(Fore.RED + 'Error' + Style.RESET_ALL) # coloredstrings import coloredstrings as cs print(cs.red('Error'))
- termcolor focuses on basic named colors but doesn’t support chaining or RGB.
coloredstringssupports truecolor, background colors, attributes, and chaining.- Example:
# termcolor from termcolor import colored print(colored('Warning!', 'yellow', attrs=['bold'])) # coloredstrings import coloredstrings as cs print(cs.bold.yellow('Warning!'))
coloredstringslacks nested styling bug presented in termcolor:# termcolor from termcolor import colored print(colored(f"Red text with {colored('underlined', attrs=['underline'])} part", "red")) # coloredstrings import coloredstrings as cs print(cs.red(f"Red text with {cs.underline('underlined')} part"))
- yachalk inspired
coloredstrings, but its mutable style builders can cause side effects. coloredstrings’sStyleBuilderis immutable, ensuring no cross-contamination between styles.- Chain syntax and API are nearly identical expect that you don't need to remember a separate method for background coloring.
- Example:
# yachalk from yachalk import chalk print(chalk.blue.bg_red.bold("Hello world!")) # coloredstrings import coloredstrings as cs print(cs.blue.on.red.blod("Hello world!"))
- rich is a full-featured library for terminal formatting, tables, markdown, and logging.
- It’s excellent for large applications but too heavy for simple coloring.
coloredstringsaims to be minimal, dependency-free, and Pythonic for everyday terminal styling.- Example:
# rich from rich.console import Console Console().print('[bold red]Error[/bold red] Something went wrong') # coloredstrings import coloredstrings as cs print(cs.bold.red('Error:'), 'Something went wrong')
In short:
| Library | No dependencies | Chainable | Truecolor | Immutable Styles | No nested styling bug | Focus |
|---|---|---|---|---|---|---|
| colorama | ✅ | ❌ | ❌ | ❌ | ✅ | Compatibility |
| termcolor | ✅ | ❌ | ❌ | ❌ | ❌ | Simplicity |
| yachalk | ✅ | ✅ | ✅ | ❌ | ✅ | Modern styling |
| rich | ❌ | ❌ | ✅ | ✅ | ✅ | Full-featured UI |
| coloredstrings | ✅ | ✅ | ✅ | ✅ | ✅ | Lightweight styling |
I’d love your help to make coloredstrings even better!
- 💡 Got an idea or found a bug? Open an issue and let’s talk about it
- 🔧 Want to improve the code? PRs are always welcome! Please include tests for any new behavior.
- ♻️ Try to keep changes backward-compatible where possible
- 🎨 Adding new styles or helpers? Don’t forget to update the README and include tests to ensure ANSI - sequences open and close correctly
- ⭐ If you like this project, consider giving it a star - it really helps others discover it!

