Skip to content
HDCharts

Customization

General patterns for styling, sizing, and interaction that apply across chart types.

Style Customization

To customize chart appearance, start from each chart's *ChartDefaults.style(...) factory and override only the fields you need.

import androidx.compose.foundation.background
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.github.hdcharts.charts.BarChart
import io.github.hdcharts.charts.model.ChartValueFormatters
import io.github.hdcharts.charts.model.toChartData
import io.github.hdcharts.charts.style.AxisLabelStyle
import io.github.hdcharts.charts.style.BarAxisStyle
import io.github.hdcharts.charts.style.BarBarsStyle
import io.github.hdcharts.charts.style.BarChartDefaults
import io.github.hdcharts.charts.style.BarGridStyle
import io.github.hdcharts.charts.style.BarSelectionLineStyle

@Composable
private fun ShowStyledBar() {
    val data = listOf(45.0, -12.0, 38.0, 27.0, -19.0, 42.0, 31.0).toChartData(
        categories = listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"),
        seriesName = "Net cash flow",
    )

    val style = BarChartDefaults.style(
        bars = BarBarsStyle(
            color = Color(0xFF0F766E),
            colors = emptyList(),
            alpha = 0.78f,
            space = 14.dp,
            minBarWidth = 10.dp,
        ),
        grid = BarGridStyle(visible = true, steps = 5, color = Color(0xFF94A3B8), lineWidth = 1.dp),
        selectionLine = BarSelectionLineStyle(visible = true, color = Color(0xFFEA580C), width = 1.dp),
        axis = BarAxisStyle(
            visible = true,
            color = Color.Gray,
            lineWidth = 1.dp,
            yLabels = AxisLabelStyle(visible = true, color = Color.Gray, size = 11.sp, count = 6),
            xLabels = AxisLabelStyle(visible = true, color = Color.Gray, size = 11.sp, count = 6),
        ),
    )

    BarChart(
        data = data,
        modifier = Modifier.background(Color(0xFFF8FAFC), RoundedCornerShape(18.dp)).padding(20.dp),
        title = "Daily Net Cash Flow",
        style = style,
        valueFormatter = ChartValueFormatters.prefix("$"),
    )
}

Chart chrome (background, shape, shadow, and outer padding) lives on the caller-supplied modifier; sizing is fully modifier-driven. The chartContainerStyle block only carries contentPadding and the title text style.

Here valueFormatter adds currency to selected raw values only; Y ticks keep the independent axisValueFormatter default. Titles do not generate labels: omitting categories hides X labels and leaves only the formatted value in selected readouts.

Sizing

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.

val dataSet = listOf(42.0, 38.0, 45.0, 51.0, 47.0, 54.0, 49.0).toChartData()

LineChart(
    data = dataSet,
    modifier = Modifier
        .fillMaxWidth()
        .height(260.dp),
)

Surrounding Chrome

Background, shadow, shape, and outer spacing are not applied by the chart. Wrap the chart in any Compose surface to add chrome.

val dataSet = listOf(42.0, 38.0, 45.0, 51.0, 47.0, 54.0, 49.0).toChartData()

Card(modifier = Modifier.padding(16.dp)) {
    LineChart(
        data = dataSet,
        modifier = Modifier
            .fillMaxWidth()
            .height(260.dp),
    )
}

Content Spacing

ChartContainerDefaults.style() returns a ChartContainerStyle with styleTitle and contentPadding. Set contentPadding to change the internal spacing reserved for axes, title, and legend.

val dataSet = listOf(42.0, 38.0, 45.0, 51.0, 47.0, 54.0, 49.0).toChartData()

LineChart(
    data = dataSet,
    modifier = Modifier.fillMaxWidth().height(260.dp),
    style = LineChartDefaults.style(
        chartContainerStyle = ChartContainerDefaults.style(contentPadding = 8.dp),
    ),
)

Selection

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")

Animation and Interaction

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.

val dataSet = listOf(42.0, 38.0, 45.0, 51.0, 47.0, 54.0, 49.0).toChartData()

LineChart(
    data = dataSet,
    modifier = Modifier.fillMaxWidth().height(260.dp),
    animateOnStart = true,
    interactionEnabled = false,
)

Responsive Layout

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),
    )
}