Split text into columns for balanced side-by-side display
Split a block of text into a chosen number of balanced columns without manually counting, cutting, or rearranging its lines.
Run — free
The result keeps every line in its original order, preserves intentional blank lines, and returns both each column's line array and a ready-to-display text value. It is useful for programs, lists, scripts, labels, and any other line-oriented material that needs a clean side-by-side presentation. The same deterministic operation can run interactively in the browser or be automated through the API.
Turn one long list into a balanced layout
Paste the complete text and choose how many columns the final display needs. The splitter treats the content as an ordered sequence of lines, then divides that sequence into contiguous groups whose sizes differ by no more than one line. When the division is uneven, the earlier columns receive the extra lines. For example, seven lines divided into three columns produce groups of three, two, and two. This approach makes the result predictable while avoiding the visual imbalance caused by putting every remainder line into the last column. Each returned column includes its one-based position, an array of its individual lines, and a text value joined with newline characters. Use the array when rendering line elements or table cells, and use the text value when inserting a whole column into a plain-text field. The original reading order remains intact from the first column through the last, so no sorting or interpretation is applied to your material.
Understand how lines and empty space are handled
Line boundaries are recognized whether the input uses Unix newlines, Windows line endings, or older carriage-return separators. The output normalizes each column's combined text to newline characters, which gives scripts a stable result across operating systems. Blank lines are meaningful and are preserved as empty strings in the line arrays; they still count toward balancing because removing them could change paragraphs, verse, forms, or carefully spaced production notes. Even an empty text value represents one empty line, matching the way splitting a text field behaves consistently. The requested column count is also honored exactly. If you ask for more columns than there are lines, the additional columns are returned with an empty line array and empty text instead of silently reducing the count. That exactness is helpful when a surrounding layout already has a fixed number of panels. No words are wrapped, measured, hyphenated, or moved between lines: prepare any desired wrapping before calling this capability.
Render, export, or automate the result safely
For a side-by-side interface, iterate over the returned columns in order and place each column in an equal-width container. Within a column, render the lines from its array to retain explicit blank rows, or display its text value in a preformatted element. A print workflow can map the same structure into page columns, labels, cue cards, or a document-generation template. Because the algorithm is deterministic and uses no network, random values, or timestamps, identical input always produces identical output. This makes it suitable for build systems, publishing pipelines, repeatable tests, and cached transformations. Validation is intentionally strict: the text must be a string, and the column count must be an integer of at least one. Invalid values fail instead of being rounded or guessed, preventing a typo such as zero, a fraction, or a numeric string from creating an unexpected layout. Browser use is available for quick work, while an API request costs $0.002 when the same transformation belongs in an automated process.
What you can do with it
Format an event program
Divide a long, ordered list of speakers or sessions into balanced blocks for a compact printed or on-screen program.
Build a multi-column checklist
Turn line-based tasks into a fixed number of panels while retaining every item and its original sequence.
Prepare publishing layouts
Feed balanced groups of lines into a document template, label generator, static site, or presentation workflow.
FAQ
How are extra lines distributed?
Column sizes differ by at most one line. When the lines do not divide evenly, the earlier columns receive one extra line each.
Are blank lines preserved?
Yes. Blank lines remain empty strings and count as lines, so paragraph spacing and intentional gaps are not discarded.
What happens if I request more columns than there are lines?
The requested number of columns is returned. Columns without assigned lines contain an empty line array and an empty text value.
Does it wrap long lines to fit a width?
No. It balances existing lines only. It does not measure display width, wrap words, hyphenate content, or modify line text.
What does the API request cost?
Each API request costs $0.002. The same deterministic splitter can also run directly in the browser.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/text/split-columns \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Alpha\nBravo\nCharlie\nDelta\nEcho\nFoxtrot\nGolf","column_count":3}'const res = await fetch("https://api.kit.forhosting.com/text/split-columns", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "Alpha\nBravo\nCharlie\nDelta\nEcho\nFoxtrot\nGolf",
"column_count": 3
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/text/split-columns",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "Alpha\nBravo\nCharlie\nDelta\nEcho\nFoxtrot\nGolf",
"column_count": 3
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/text/split-columns", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"Alpha\\nBravo\\nCharlie\\nDelta\\nEcho\\nFoxtrot\\nGolf","column_count":3}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"Alpha\nBravo\nCharlie\nDelta\nEcho\nFoxtrot\nGolf","column_count":3}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/text/split-columns", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "Alpha\nBravo\nCharlie\nDelta\nEcho\nFoxtrot\nGolf",
"column_count": 3
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "text.split_columns",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_tokens | 20000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |