Skip to content

VizGhar/CellarKt

Repository files navigation

CellarKt

Maven Central License: MIT Kotlin

CellarKt is a Kotlin Multiplatform library for generating XLSX (Excel) documents entirely in-memory — no JVM spreadsheet engine, no native dependencies, just pure Kotlin.

Write-only. CellarKt creates XLSX files. It does not read or parse existing spreadsheets.

CellarKt was built to cover the common cases for a multiplatform Kotlin application. It is not a full replacement for Apache POI or other comprehensive spreadsheet libraries, but it handles the vast majority of real-world reporting needs.

Targets: Android · iOS (arm64 + simulatorArm64)

Table of Contents

Installation

// build.gradle.kts
dependencies {
    implementation("xyz.kandrac:cellar:0.0.1")
}

Requirements:

  • Kotlin 2.1+
  • Kotlinx Coroutines 1.10+
  • Android: compileSdk 37+, minSdk 26+
  • iOS: arm64 / simulatorArm64

Quick Start

suspend fun createReport(): ByteArray = cellar {
    sheet("Report") {
        // Place cells at explicit coordinates (0-based)
        cell("Employee Timesheet", x = 0, y = 0, horizontalSpan = 4)

        // Sequential rows (left-to-right)
        row(y = 1) {
            cell("Name"); cell("Role"); cell("Hours"); cell("Rate")
        }

        // Typed convenience overloads
        row(y = 2) {
            cell("Alice")
            cell("Engineer")
            cell(40)            // Int → Number
            cell(42.50)         // Double → Number
        }

        // Formula (no leading "=")
        formula("C3*D3", x = 3, y = 2)

        // Date (days since Unix epoch)
        date(20241L, x = 0, y = 4, format = DateFormat.Custom("dd/mm/yyyy"))

        // Boolean
        cell(true, x = 1, y = 4)

        // Error
        error(ExcelError.DivisionByZero, x = 2, y = 4)
    }
}.export()

.export() is a suspend function that runs on Dispatchers.Default. The returned ByteArray can be written to a file, shared via a content URI, or sent over the network.

DSL Overview

The entire document is built inside a cellar { } lambda:

cellar {
    metadata { ... }          // Optional: author, timestamps, app info
    default { ... }           // Optional: document-wide font & format defaults
    sheet("Sheet1") { ... }   // One or more worksheets
    namedRange(...)           // Optional: workbook-level named ranges
}.export()

Cell Placement

Function Description
cell(value, x, y, horizontalSpan, verticalSpan, style) Place at explicit (x, y) coordinates with optional merge
row(y, startX = 0) { cell(...) } Sequential cells left-to-right
column(x, startY = 0) { cell(...) } Sequential cells top-to-bottom

You can also use columnWidth(x, width) and rowHeight(y, height) to control dimensions.

Cell overlap (including merged cells) is detected at build time — an IllegalStateException is thrown when two cells occupy the same range.

Cell Types

Type DSL Function OOXML Representation
Text cell("Hello") Shared string or inline string
Number (Int/Double/Long/Float) cell(42), cell(3.14) Numeric cell
Boolean cell(true) t="b"
Formula formula("SUM(A1:A10)") <f> element (no leading =)
Array Formula cell(CellValue.ArrayFormula(...)) <f t="array">
Date date(epochDay) Serial number with date format
Date+Time dateTime(epochMillis) Fractional serial with datetime format
Time time(millisOfDay) Fractional serial with time format
Error error(ExcelError.Value) t="e"
Empty Omitted Empty cell

Styling

Use the style parameter on any cell() call to apply fonts, borders, background, and alignment:

cell("Header", x = 0, y = 0, style = CellStyle(
    font = Font(size = 14, bold = true, color = ExcelColor.White),
    background = Background(ExcelColor("FF1A73E8")),
    border = Border.All,
    horizontalAlignment = HorizontalAlignment.Center,
    verticalAlignment = VerticalAlignment.Center,
))

Font

Font(
    size = 11,                     // Font size in points
    bold = false,
    italic = false,
    underline = false,
    color = null,                  // ExcelColor ARGB or null for default
    name = "Calibri",              // Font family name
)

Border

Border(
    top = BorderLine.Thin,
    bottom = BorderLine.Thin,
    left = BorderLine.Thin,
    right = BorderLine.Thin,
)
// Shorthand:
Border.All       // Thin on all sides
Border.AllThick  // Thick on all sides

Background

Background(color = ExcelColor("FFFF0000"))  // ARGB hex
Background()  // Transparent (default)

Alignment

HorizontalAlignment.Start | Center | End
VerticalAlignment.Top     | Center | Bottom

Number Format Presets

NumberFormat.Integer        // "#,##0"
NumberFormat.Decimal2       // "#,##0.00"
NumberFormat.Percent        // "0%"
NumberFormat.Dollar         // "$#,##0.00"
NumberFormat.Euro           // "€#,##0.00"
NumberFormat.Scientific     // "0.00E+00"
// … plus many more, or any custom format string

Example:

cell(1234567.89, x = 0, y = 0, style = CellStyle(numberFormat = NumberFormat.Decimal2))

Formulas

Formulas are written without the leading =:

formula("SUM(C2:C10)", x = 0, y = 11)
formula("A1*B1", x = 2, y = 3)

For array formulas (CSE, Ctrl+Shift+Enter) use the CellValue.ArrayFormula type directly:

cell(CellValue.ArrayFormula("SUM(B2:B11*C2:C11)", arrayRef = "A12"), x = 0, y = 11)

Dates & Times

Date/time values are specified in terms of the Unix epoch and automatically converted to Excel serial numbers:

DSL Function Input Excel Representation
date(epochDay, format) Days since 1970-01-01 Integer serial
dateTime(epochMillis, format) ms since 1970-01-01 UTC Fractional serial
time(millisOfDay, format) ms since midnight (0–86,399,999) Decimal 0.0–1.0
// Using kotlinx-datetime:
date(LocalDate(2025, 6, 1).toEpochDays().toLong(), x = 0, y = 0)
dateTime(Clock.System.now().toEpochMilliseconds(), x = 0, y = 0)
time(LocalTime(14, 30).toMillisecondOfDay().toLong(), x = 0, y = 0)

Built-in display presets in DateFormat:

Preset Format String Excel Built-in ID
ShortDate mm-dd-yy 14
MediumDate d-mmm-yy 15
MonthYear mmm-yy 17
ShortDateTime m/d/yy h:mm 22
ShortTime h:mm 20
LongTime h:mm:ss 21
Custom("dd/MM/yyyy") Any format code 164+

Document Metadata

Optional document properties written to docProps/core.xml and docProps/app.xml:

cellar {
    metadata {
        author              = "Alice"
        lastModifiedBy      = "Bob"
        createdEpochMillis  = 1_700_000_000_000L
        modifiedEpochMillis = 1_700_000_000_000L
        appName             = "ReportGenerator"
        appVersion          = "1.0"
        company             = "Acme Corp"
    }
    //
}

All fields are nullable and omitted from the output when unset.

Default Formats

Set document-wide defaults that apply to all cells unless overridden:

cellar {
    default {
        font           = Font(size = 12, name = "Arial")
        numberFormat   = NumberFormat.Decimal2
        dateFormat     = DateFormat.Custom("dd/MM/yyyy")
        dateTimeFormat = DateFormat.Custom("dd/MM/yyyy HH:mm")
        timeFormat     = DateFormat.LongTime
    }
    //
}

Named Ranges

Define workbook-level names that can be used in formulas:

cellar {
    sheet("Data") { /**/ }
    namedRange("TaxRate", ref = "Data!$C$1")
    namedRange("TotalRevenue", ref = "Data!$B$2:$B$10")
}
// Usage in a formula:
formula("TotalRevenue * TaxRate", x = 0, y = 5)

Style Resolution Priority

Settings are resolved in this order (highest priority first):

Property Cell Style Document Default Library Fallback
Font CellStyle.font CellarDefaults.font Font() (11pt Calibri)
Number format CellStyle.numberFormat CellarDefaults.numberFormat General
Date format CellStyle.numberFormat / CellStyle.dateFormat / cell value format CellarDefaults.dateFormat/timeFormat/dateTimeFormat ShortDate / ShortTime / ShortDateTime
Border CellStyle.border Border() (none)
Background CellStyle.background Background() (none)

Limitations

CellarKt is intentionally focused on the common spreadsheet generation use cases. Known missing features include:

  • Rich text, text wrapping, rotation, indentation
  • Sheet tab color, freeze panes, zoom, auto-filter, print settings
  • Excel tables (ListObject), conditional formatting, data validation
  • Images, charts, shapes, sparklines
  • Cell comments, hyperlinks, sheet protection
  • ZIP compression (uses STORED method only, no DEFLATE)
  • Reading/parsing existing XLSX files

See missing_features.md for the full list.

Large spreadsheets. CellarKt builds the entire document in memory, so it is not suitable for generating very large spreadsheets (millions of rows).

Contributing

Contributions are welcome! Whether it's a bug report, a feature request, or a pull request — please open an issue or submit a PR.

This project is licensed under the MIT License.

About

Kotlin multiplatform in memory XSLX writer

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages