Guide
Set Column Width and Row Height in openpyxl
Set Excel column widths and row heights from Python with openpyxl, build an auto-fit pass by measuring content, hide columns, and set sensible defaults — runnable.
openpyxl gives you direct control over how wide each column is and how tall each row is, but the units are not pixels and there is no real auto-fit — you compute it yourself. This guide, part of Styling Excel Cells with openpyxl, shows the exact calls, an auto-fit pass you can drop into any generator, plus hiding and defaults. Every block runs in order against a sample workbook built first.
Install and create a sample workbook
pip install openpyxl
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.title = "Inventory"
ws.append(["SKU", "Product Name", "Warehouse Location", "Qty"])
for row in [
["A-1001", "Stainless Steel Water Bottle", "Aisle 12, Bin 4", 340],
["A-1002", "Bamboo Cutting Board", "Aisle 3, Bin 19", 88],
["A-1003", "Ceramic Pour-Over Dripper", "Aisle 7, Bin 2", 152],
]:
ws.append(row)
wb.save("sized_report.xlsx")
print("Sample workbook created")
Set column width
Set a column's width through ws.column_dimensions[letter].width. The unit is approximately the number of characters of the default font that fit in the column — not pixels. A width of 10 shows roughly 10 characters:
from openpyxl import load_workbook
wb = load_workbook("sized_report.xlsx")
ws = wb["Inventory"]
ws.column_dimensions["A"].width = 12 # SKU
ws.column_dimensions["B"].width = 32 # Product Name (longest text)
ws.column_dimensions["C"].width = 22 # Warehouse Location
ws.column_dimensions["D"].width = 8 # Qty
wb.save("sized_report.xlsx")
print("Column widths set")
You always index column_dimensions by the column letter ("A", "B", ...), never by a number. If you have a 1-based index, convert it with get_column_letter.
Set row height
Set a row's height through ws.row_dimensions[index].height. Here the unit is points (1/72 inch), the same unit as font size. Give the header room and bump a data row:
from openpyxl import load_workbook
wb = load_workbook("sized_report.xlsx")
ws = wb["Inventory"]
ws.row_dimensions[1].height = 24 # taller header
ws.row_dimensions[2].height = 18 # one roomier data row
wb.save("sized_report.xlsx")
print("Row heights set")
Auto-fit columns by measuring content
openpyxl has no true auto-fit, so you compute a width from the longest value in each column. Walk every cell, take len(str(value)), track the per-column maximum, add a small padding, then assign it. Convert the column index to a letter with get_column_letter:
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
wb = load_workbook("sized_report.xlsx")
ws = wb["Inventory"]
for col_cells in ws.columns:
longest = 0
letter = get_column_letter(col_cells[0].column) # .column is 1-based int
for cell in col_cells:
if cell.value is not None:
longest = max(longest, len(str(cell.value)))
ws.column_dimensions[letter].width = longest + 2 # padding
wb.save("sized_report.xlsx")
print("Columns auto-fitted")
This is an approximation: character count ignores font, bold weight, and proportional glyph widths, so wide content in a bold or large font may still clip slightly. Clamp the result with min(longest + 2, 60) if a single long value would otherwise blow out the layout.
Hide a column
Hide a column without deleting its data by setting hidden=True on its dimension. The data stays in the file and reappears if the user unhides it:
from openpyxl import load_workbook
wb = load_workbook("sized_report.xlsx")
ws = wb["Inventory"]
ws.column_dimensions["C"].hidden = True # hide Warehouse Location
wb.save("sized_report.xlsx")
print("Column C hidden")
The same attribute exists for rows: ws.row_dimensions[2].hidden = True.
Set a default width and height
Apply a baseline size to every column or row through the sheet's sheet_format. Per-column and per-row settings still override the default where you set them:
from openpyxl import load_workbook
wb = load_workbook("sized_report.xlsx")
ws = wb["Inventory"]
ws.sheet_format.defaultColWidth = 15
ws.sheet_format.defaultRowHeight = 16
wb.save("sized_report.xlsx")
print("Defaults set")
Common pitfalls
| Symptom | Cause | Fix |
|---|---|---|
| Columns far too narrow or wide | Treating width as pixels | width ≈ character count of the default font; a value of 30 is ~30 characters |
KeyError or no effect when sizing a column | Indexing column_dimensions by a number | Use the letter: column_dimensions["B"], or convert with get_column_letter(idx) |
| Row height ignored | Confusing height units with width units | Row height is in points (like font size), not characters |
| "Auto-fit" call not found | openpyxl has no autofit() | Measure len(str(value)) per column and set width yourself |
| Wide font still clips | Character count ignores bold/large fonts | Add extra padding or measure against the actual font if exactness matters |
| Hidden column lost its data | Confusing hidden=True with deletion | hidden=True keeps the data; only ws.delete_cols() removes it |
A note on scale
The auto-fit pass iterates every cell, so for sheets with hundreds of thousands of rows it gets slow and memory-heavy. Sample the first few hundred rows, or cap the measured length, instead of scanning the whole column — the header plus a representative slice usually gives a good enough width.
Frequently asked questions
What unit is column width in openpyxl?
Roughly the number of characters of the workbook's default font that fit in the column. It is not pixels and not points. A width of 20 shows about 20 characters.
What unit is row height? Points — 1/72 of an inch, the same unit used for font size. A 14-point font fits comfortably in a row about 18 points tall.
How do I auto-fit columns?
openpyxl cannot measure rendered text, so there is no built-in auto-fit. Loop the cells, take the longest len(str(value)) per column, add padding, and assign it to column_dimensions[letter].width.
Why do I get a KeyError when setting a width?
You indexed column_dimensions with a number. It is keyed by column letter. Convert an index with from openpyxl.utils import get_column_letter.
Does hiding a column delete its data?
No. ws.column_dimensions["C"].hidden = True only hides it; the values remain in the file and reappear when unhidden. Use ws.delete_cols() to actually remove a column.
Conclusion
Column width is set in approximate character units through ws.column_dimensions[letter].width, and row height in points through ws.row_dimensions[index].height. There is no native auto-fit, so measure len(str(value)) per column and pad the result — clamping it for safety. Index columns by letter, convert from numbers with get_column_letter, and use hidden=True plus sheet_format defaults to round out the layout.
Where to go next
- Styling Excel Cells with openpyxl — the parent cluster covering fonts, fills, borders, and alignment.
- Freeze the Header Row in Excel with openpyxl — keep the header visible once the sheet is wide.
- Using openpyxl for Excel File Manipulation — workbook fundamentals behind these sizing calls.