charts
2.2.0indexedSimple chart library offering animated, customizable chart styles, including pie, line, multiline, bar, and stacked bar charts. Supports various data sets and M3 theme integration.
Simple chart library offering animated, customizable chart styles, including pie, line, multiline, bar, and stacked bar charts. Supports various data sets and M3 theme integration.
A Kotlin Multiplatform chart library built with Jetpack Compose.
https://charts.hdcode.dev/demo
https://charts.hdcode.dev/demo/snapshot/
https://charts.hdcode.dev/playground
[!IMPORTANT] To try HDCharts, use the latest snapshot. It is the most capable build, with many new features and bug fixes. Add
maven("https://central.sonatype.com/repository/maven-snapshots/")to your repositories to use it.
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}
Use the umbrella artifact when you want all chart types with the simplest setup.
commonMain.dependencies {
implementation("io.github.hdcharts:charts:<version>")
}
Use independent modules when you want only specific chart types and smaller dependency footprint.
commonMain.dependencies {
implementation("io.github.hdcharts:line:<version>")
implementation("io.github.hdcharts:pie:<version>")
implementation("io.github.hdcharts:bar:<version>")
implementation("io.github.hdcharts:histogram:<version>")
implementation("io.github.hdcharts:stacked-bar:<version>")
implementation("io.github.hdcharts:stacked-area:<version>")
implementation("io.github.hdcharts:radar:<version>")
}
Use BOM for version alignment where Gradle platforms are supported.
For KMP commonMain, keep explicit versions as shown above.
dependencies {
implementation(platform("io.github.hdcharts:bom:<version>"))
implementation("io.github.hdcharts:line")
implementation("io.github.hdcharts:pie")
implementation("io.github.hdcharts:bar")
implementation("io.github.hdcharts:histogram")
implementation("io.github.hdcharts:stacked-bar")
implementation("io.github.hdcharts:stacked-area")
implementation("io.github.hdcharts:radar")
}
@Composable
fun BasicLineChart() {
values = listOf(, , , , , , )
labels = listOf(, , , , , , )
dataSet = values.toChartData(
categories = labels,
)
LineChart(
= dataSet,
modifier = Modifier
.fillMaxWidth()
.height(dp),
)
}
The chart modifier controls its size and placement. Surrounding chrome stays
with the consumer:
Card {
LineChart(
data = dataSet,
modifier = Modifier
.fillMaxWidth()
.height(260.dp),
)
}
The chart composable's modifier is the only sizing control. A bounded modifier becomes a
rectangular plot; a one-axis bounded modifier derives a square fallback; a fully unbounded
modifier falls back to a 200.dp default.
LineChart(
data = dataSet,
modifier = Modifier
.fillMaxWidth()
.height(260.dp),
)
Background, shadow, shape, and outer spacing are not applied by the chart. Wrap the chart in any Compose surface to add chrome.
Card(modifier = Modifier.padding(16.dp)) {
LineChart(
data = dataSet,
modifier = Modifier.fillMaxWidth().height(260.dp),
)
}
ChartContainerDefaults.style() returns a ChartContainerStyle with styleTitle and
contentPadding. Set contentPadding to change the internal spacing reserved for axes,
title, and legend.
LineChart(
data = dataSet,
modifier = Modifier.fillMaxWidth().height(260.dp),
style = LineChartDefaults.style(
chartContainerStyle = ChartContainerDefaults.style(contentPadding = 8.dp),
),
)
Each chart module exposes its own *Defaults.style() factory. Use named arguments to customize
only the parts you care about. The example below customizes line color, axis, points, and zoom
controls; everything else keeps its default.
LineChart(
data = dataSet,
title = "Daily Support Tickets",
modifier = Modifier.fillMaxWidth().height(dp),
style = LineChartDefaults.style(
chartContainerStyle = ChartContainerDefaults.style(),
line = LineVisualStyle(
color = Color(),
alpha = ,
colors = emptyList(),
strokeWidth = dp,
bezier = ,
),
points = LinePointStyle(color = Color(), size = dp, visible = ),
axis = LineAxisStyle(
visible = ,
color = Color.Gray,
lineWidth = dp,
yLabels = AxisLabelStyle(visible = , color = Color.Gray, size = sp, maxCount = ),
xLabels = AxisLabelStyle(visible = , color = Color.Gray, size = sp, maxCount = ),
),
zoomControlsVisible = ,
),
)
By default the Y-axis is derived from the data, which can make small fluctuations look
exaggerated when the axis doesn't start at zero. Set range on *Defaults.style() to pin
min, max, or both, independently of one another; whichever bound you leave null keeps
deriving from the data.
LineChart(
data = dataSet,
modifier = Modifier.fillMaxWidth().height(260.dp),
style = LineChartDefaults.style(
range = LineChartDefaults.range(min = 0.0, max = 100.0),
),
)
BarChart exposes the same range block on BarChartDefaults.style().
Use rememberChartSelection() to hoist selection. The chart calls back into it; you read
selectedIndex to drive external UI such as legends or summary cards.
val selection = rememberChartSelection()
val values = listOf(42.0, 38.0, 45.0, 51.0, 47.0, 54.0, 49.0)
LineChart(
data = values.toChartData(),
modifier = Modifier.fillMaxWidth().height(260.dp),
selection = selection,
)
val selected = values.getOrNull(selection.selectedIndex ?: 0)
Text("Selected: $selected")
Compose the chart with any layout, including Row, Column, LazyColumn, or BoxWithConstraints.
A bounded modifier is always honored; an unbounded one falls back to the documented defaults.
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
LineChart(
data = lineData,
modifier = Modifier.fillMaxWidth().height(220.dp),
)
Spacer(modifier = Modifier.height(16.dp))
BarChart(
data = barData,
modifier = Modifier.fillMaxWidth().height(220.dp),
)
}
animateOnStart controls the initial reveal animation; interactionEnabled disables gestures,
selection, and zoom controls together. Disable interaction to embed a chart inside a tappable
card without conflicts.
LineChart(
data = dataSet,
modifier = Modifier.fillMaxWidth().height(260.dp),
animateOnStart = true,
interactionEnabled = false,
)
See CONTRIBUTING.md for contribution guidelines.
Surfaced from shared tags and platforms — no rankings paid for.