# Line Chart Dots

A weight trend with a dot at every monthly reading and a fixed value axis on the right.

Line Chart Dots is an open-source chart from suiss/ui for React, React Native, SwiftUI and Jetpack Compose. The @esuiss/ui CLI copies its source into your project, so you own the code.

Source: https://ui.suiss.app/docs/charts/line-chart-dots

**React**

**Example**

```tsx title="components/charts/line-chart-dots.tsx"
"use client"

import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"

import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
} from "@/components/ui/chart"

const chartData = [
  82.4, 81.6, 81.9, 80.8, 80.1, 79.6, 79.8, 78.9, 78.4, 77.9,
].map((weight, index) => ({
  month: new Intl.DateTimeFormat("en-US", { month: "short" }).format(
    new Date(2026, index, 1)
  ),
  weight,
}))

const chartConfig = {
  weight: { label: "Weight", color: "var(--color-purple-500)" },
} satisfies ChartConfig

export function LineChartDots() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <p className="text-sm font-semibold text-[color-mix(in_oklab,var(--color-purple-500),var(--foreground)_15%)] dark:text-purple-500">
          Weight
        </p>
        <p className="flex items-baseline gap-1">
          <span className="text-3xl font-semibold tracking-tight tabular-nums">
            77.9
          </span>
          <span className="text-base font-semibold text-muted-foreground">
            kg
          </span>
        </p>
        <p className="text-sm text-muted-foreground">
          Down 4.5 kg since January
        </p>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-40 w-full"
        >
          <LineChart
            accessibilityLayer
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="month"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              interval={2}
            />
            <YAxis
              orientation="right"
              tickLine={false}
              axisLine={false}
              tickMargin={6}
              width="auto"
              domain={[76, 84]}
              ticks={[76, 80, 84]}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  hideIndicator
                  formatter={(value) => (
                    <span className="font-semibold tabular-nums">
                      {value} kg
                    </span>
                  )}
                />
              }
            />
            <Line
              dataKey="weight"
              type="linear"
              stroke="var(--color-weight)"
              strokeWidth={2}
              dot={{ r: 3.5, fill: "var(--color-weight)", strokeWidth: 0 }}
              activeDot={{ r: 5 }}
            />
          </LineChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

A health-style weight card with a dot on every monthly reading and a fixed value axis on the right. The dots make it clear where measurements actually exist, so use this variant when readings are sparse or irregular.

## Installation

### CLI

```bash title="Terminal"
npx shadcn@latest add @esuiss/line-chart-dots
```

Works in any project with a `components.json`. See [Installation](https://ui.suiss.app/docs/installation#add-components) for the one-line registry setup. Or use the suiss/ui CLI:

```bash title="Terminal"
npx @esuiss/ui@latest add charts line-chart-dots
```

### Manual

1. Install the dependencies:

```bash title="Terminal"
npm install recharts
```

2. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart).

3. Copy the source into `components/charts/line-chart-dots.tsx`:

```tsx title="components/charts/line-chart-dots.tsx"
"use client"

import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"

import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
} from "@/components/ui/chart"

const chartData = [
  82.4, 81.6, 81.9, 80.8, 80.1, 79.6, 79.8, 78.9, 78.4, 77.9,
].map((weight, index) => ({
  month: new Intl.DateTimeFormat("en-US", { month: "short" }).format(
    new Date(2026, index, 1)
  ),
  weight,
}))

const chartConfig = {
  weight: { label: "Weight", color: "var(--color-purple-500)" },
} satisfies ChartConfig

export function LineChartDots() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <p className="text-sm font-semibold text-[color-mix(in_oklab,var(--color-purple-500),var(--foreground)_15%)] dark:text-purple-500">
          Weight
        </p>
        <p className="flex items-baseline gap-1">
          <span className="text-3xl font-semibold tracking-tight tabular-nums">
            77.9
          </span>
          <span className="text-base font-semibold text-muted-foreground">
            kg
          </span>
        </p>
        <p className="text-sm text-muted-foreground">
          Down 4.5 kg since January
        </p>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-40 w-full"
        >
          <LineChart
            accessibilityLayer
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="month"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              interval={2}
            />
            <YAxis
              orientation="right"
              tickLine={false}
              axisLine={false}
              tickMargin={6}
              width="auto"
              domain={[76, 84]}
              ticks={[76, 80, 84]}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  hideIndicator
                  formatter={(value) => (
                    <span className="font-semibold tabular-nums">
                      {value} kg
                    </span>
                  )}
                />
              }
            />
            <Line
              dataKey="weight"
              type="linear"
              stroke="var(--color-weight)"
              strokeWidth={2}
              dot={{ r: 3.5, fill: "var(--color-weight)", strokeWidth: 0 }}
              activeDot={{ r: 5 }}
            />
          </LineChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

4. Update the import paths to match your project.

## Usage

```tsx
import { LineChartDots } from "@/components/charts/line-chart-dots"
```

```tsx
<LineChartDots />
```

Replace the list of readings in `chartData` and rename `weight` in the data, the line and `chartConfig`. Set the value axis `domain` and `ticks` to a range that suits your numbers, and change the unit in the tooltip formatter.

## Notes

The headline value and the change below it are hard-coded text, so update them along with the data or compute them from it.

**React Native, SwiftUI, Jetpack Compose**

![Preview](https://ui.suiss.app/previews/charts-line--dots.light.webp)

```tsx title="uniwind/components/charts/line-chart-dots.tsx"
import { View } from "react-native"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  CartesianGrid,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  Line,
  LineChart,
  XAxis,
  YAxis,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"

const MONTHS = [
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sep",
  "Oct",
]

const chartData = [
  82.4, 81.6, 81.9, 80.8, 80.1, 79.6, 79.8, 78.9, 78.4, 77.9,
].map((weight, index) => ({ month: MONTHS[index] ?? "", weight }))

const chartConfig = {
  weight: { label: "Weight", color: "purple-500" },
} satisfies ChartConfig

export function LineChartDots() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <Text className="text-sm font-semibold text-purple-500">Weight</Text>
        <View className="flex-row items-baseline gap-1">
          <Text className="text-3xl font-semibold tracking-tight tabular-nums">
            77.9
          </Text>
          <Text className="text-base font-semibold text-muted-foreground">
            kg
          </Text>
        </View>
        <Text className="text-sm text-muted-foreground">
          Down 4.5 kg since January
        </Text>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Weight"
          className="h-40 w-full"
        >
          <LineChart
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis dataKey="month" tickMargin={8} interval={2} />
            <YAxis
              orientation="right"
              tickMargin={6}
              width="auto"
              domain={[76, 84]}
              ticks={[76, 80, 84]}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  hideIndicator
                  formatter={(value) => (
                    <Text className="font-semibold tabular-nums">
                      {String(value)} kg
                    </Text>
                  )}
                />
              }
            />
            <Line
              dataKey="weight"
              type="linear"
              strokeWidth={2}
              dot={{ r: 3.5 }}
              activeDot={{ r: 5 }}
            />
          </LineChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

```swift title="swift/Charts/LineChartDots.swift"
import Charts
import SwiftUI

private let chartData: [(month: String, weight: Double)] = [
  ("Jan", 82.4), ("Feb", 81.6), ("Mar", 81.9), ("Apr", 80.8), ("May", 80.1),
  ("Jun", 79.6), ("Jul", 79.8), ("Aug", 78.9), ("Sep", 78.4), ("Oct", 77.9),
]

private let chartConfig: ChartConfig = [
  "weight": .init("Weight", color: Palette.purple500),
]

public struct LineChartDots: View {
  @State private var selection: Int?

  public init() {}

  public var body: some View {
    Card(.filled, size: .sm) {
      VStack(alignment: .leading, spacing: 2) {
        Text("Weight")
          .textStyle(.sm, weight: .semibold)
          .foregroundStyle(chartConfig.color("weight"))
        HStack(alignment: .firstTextBaseline, spacing: 4) {
          Text(verbatim: "77.9")
            .textStyle(.xl3, weight: .semibold)
            .monospacedDigit()
          Text("kg")
            .textStyle(.base, weight: .semibold)
            .foregroundStyle(EsuissColor.mutedForeground)
        }
        Text("Down 4.5 kg since January")
          .textStyle(.sm)
          .foregroundStyle(EsuissColor.mutedForeground)
      }
      .padding(.horizontal, 16)
      CardContent {
        ChartContainer(config: chartConfig) {
          ChartAnimator { progress in
            Chart {
              ForEach(chartData.indices, id: \.self) { index in
                LineMark(x: .value("Month", index), y: .value("Weight", chartData[index].weight))
                  .interpolationMethod(.linear)
                  .lineStyle(StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round))
                  .foregroundStyle(chartConfig.color("weight"))
                PointMark(x: .value("Month", index), y: .value("Weight", chartData[index].weight))
                  .symbolSize(selection == index ? 100 : 49)
                  .foregroundStyle(chartConfig.color("weight"))
              }
              .chartReveal(progress, x: 0...(chartData.count - 1))
            }
            .chartXScale(domain: 0...(chartData.count - 1), range: .plotDimension(padding: 12))
            .chartYScale(domain: 76...84)
            .chartXAxis { ChartAxis.x(values: [0, 3, 6, 9]) { chartData[$0].month } }
            .chartYAxis { ChartAxis.y(values: [76, 80, 84]) { (value: Double) in value.formatted() } }
            .chartTooltip(
              x: Array(chartData.indices),
              labels: chartData.map(\.month),
              selection: $selection,
              accessibilityLabel: "Weight",
              items: { [ChartTooltipItem("weight", value: chartData[$0].weight)] }
            ) { payload in
              ChartTooltipContent(payload, hideIndicator: true) { item in
                Text("\(item.value, format: .number) kg")
                  .scaledFont(TextStyle.xs, weight: .semibold)
                  .monospacedDigit()
              }
            }
          }
        }
        .frame(height: 160)
      }
    }
  }
}
```

```kt title="kotlin/charts/LineChartDots.kt"
package com.esuiss.ui.charts

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Card
import com.esuiss.ui.components.CardContent
import com.esuiss.ui.components.CardSize
import com.esuiss.ui.components.CardVariant
import com.esuiss.ui.components.ChartAxisOrientation
import com.esuiss.ui.components.ChartConfig
import com.esuiss.ui.components.ChartConfigItem
import com.esuiss.ui.components.ChartContainer
import com.esuiss.ui.components.ChartDot
import com.esuiss.ui.components.ChartMargin
import com.esuiss.ui.components.ChartTooltipContent
import com.esuiss.ui.components.LineChart
import com.esuiss.ui.theme.EsuissTheme
import com.esuiss.ui.theme.Palette
import com.esuiss.ui.theme.Typography

private class LineDotsRow(val month: String, val weight: Double)

private val months = listOf("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")

private val chartData = listOf(82.4, 81.6, 81.9, 80.8, 80.1, 79.6, 79.8, 78.9, 78.4, 77.9)
    .mapIndexed { index, weight -> LineDotsRow(months[index], weight) }

private val chartConfig = ChartConfig(
    "weight" to ChartConfigItem("Weight") { Palette.purple500 },
)

@Composable
fun LineChartDots(modifier: Modifier = Modifier) {
    val colors = EsuissTheme.colors
    val number = Typography.xl3.copy(color = colors.foreground, fontWeight = FontWeight.SemiBold, fontFeatureSettings = "tnum")
    Card(modifier, variant = CardVariant.Filled, size = CardSize.Sm) {
        CardContent {
            Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
                BasicText(
                    "Weight",
                    style = Typography.sm.copy(
                        color = if (colors.isDark) Palette.purple500 else lerp(Palette.purple500, colors.foreground, 0.15f),
                        fontWeight = FontWeight.SemiBold,
                    ),
                )
                Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
                    BasicText("77.9", Modifier.alignByBaseline(), style = number)
                    BasicText(
                        "kg",
                        Modifier.alignByBaseline(),
                        style = Typography.base.copy(color = colors.mutedForeground, fontWeight = FontWeight.SemiBold),
                    )
                }
                BasicText("Down 4.5 kg since January", style = Typography.sm.copy(color = colors.mutedForeground))
            }
        }
        CardContent {
            ChartContainer(
                chartConfig,
                Modifier
                    .fillMaxWidth()
                    .height(160.dp),
            ) {
                LineChart(
                    chartData,
                    margin = ChartMargin(top = 10.dp, right = 4.dp, bottom = 0.dp, left = 12.dp),
                    accessibilityLabel = "Weight",
                ) {
                    CartesianGrid(strokeDasharray = listOf(2f, 4f))
                    XAxis(label = { it.month }, tickMargin = 8.dp, interval = 2)
                    YAxis(
                        orientation = ChartAxisOrientation.Right,
                        tickMargin = 6.dp,
                        domain = 76.0..84.0,
                        ticks = listOf(76.0, 80.0, 84.0),
                        tickFormatter = { it.toInt().toString() },
                    )
                    ChartTooltip {
                        ChartTooltipContent(
                            hideIndicator = true,
                            formatter = { item ->
                                BasicText(
                                    "${item.value} kg",
                                    style = Typography.xs.copy(color = colors.foreground, fontWeight = FontWeight.SemiBold, fontFeatureSettings = "tnum"),
                                )
                            },
                        )
                    }
                    Line(
                        "weight",
                        value = { it.weight },
                        strokeWidth = 2.dp,
                        dot = ChartDot(3.5.dp),
                        activeDot = ChartDot(5.dp),
                    )
                }
            }
        }
    }
}
```

Ten monthly weights drawn with `type="linear"` and a dot on every reading, plus a larger dot for the touched point. A value axis on the right covers a fixed range, and the tooltip formats values in kilograms. The header shows the latest weight and the change since January as static text.

## Installation

**React Native**

```bash title="Terminal"
npx shadcn@latest add @esuiss-rn/line-chart-dots
```

See [Installation](https://ui.suiss.app/docs/installation) for the `components.json` setup. Or use the suiss/ui CLI:

```bash title="Terminal"
npx @esuiss/ui@latest add line-chart-dots
```

**SwiftUI**

```bash title="Terminal"
npx @esuiss/ui@latest add line-chart-dots --platform swift
```

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add line-chart-dots --platform kotlin
```

The CLI also adds what it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart), [Text](https://ui.suiss.app/docs/components/text).

### Manual

**React Native**

**Uniwind**

1. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart), [Text](https://ui.suiss.app/docs/components/text).

2. Copy the source into `components/charts/line-chart-dots.tsx`:

- `uniwind/components/charts/line-chart-dots.tsx`: shown above

3. Update the import paths to match your project.

**NativeWind**

1. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart), [Text](https://ui.suiss.app/docs/components/text).

2. Copy the source into `components/charts/line-chart-dots.tsx`:

```tsx title="nativewind/components/charts/line-chart-dots.tsx"
import { View } from "react-native"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  CartesianGrid,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  Line,
  LineChart,
  XAxis,
  YAxis,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"

const MONTHS = [
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sep",
  "Oct",
]

const chartData = [
  82.4, 81.6, 81.9, 80.8, 80.1, 79.6, 79.8, 78.9, 78.4, 77.9,
].map((weight, index) => ({ month: MONTHS[index] ?? "", weight }))

const chartConfig = {
  weight: { label: "Weight", color: "purple-500" },
} satisfies ChartConfig

export function LineChartDots() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <Text className="text-sm font-semibold text-purple-500">Weight</Text>
        <View className="flex-row items-baseline gap-1">
          <Text className="text-3xl font-semibold tracking-tight tabular-nums">
            77.9
          </Text>
          <Text className="text-base font-semibold text-muted-foreground">
            kg
          </Text>
        </View>
        <Text className="text-sm text-muted-foreground">
          Down 4.5 kg since January
        </Text>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Weight"
          className="h-40 w-full"
        >
          <LineChart
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis dataKey="month" tickMargin={8} interval={2} />
            <YAxis
              orientation="right"
              tickMargin={6}
              width="auto"
              domain={[76, 84]}
              ticks={[76, 80, 84]}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  hideIndicator
                  formatter={(value) => (
                    <Text className="font-semibold tabular-nums">
                      {String(value)} kg
                    </Text>
                  )}
                />
              }
            />
            <Line
              dataKey="weight"
              type="linear"
              strokeWidth={2}
              dot={{ r: 3.5 }}
              activeDot={{ r: 5 }}
            />
          </LineChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

3. Update the import paths to match your project.

**StyleSheet**

1. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart), [Text](https://ui.suiss.app/docs/components/text).

2. Copy the source into `components/charts/line-chart-dots.tsx`:

```tsx title="stylesheet/components/charts/line-chart-dots.tsx"
import { StyleSheet, View } from "react-native"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  CartesianGrid,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  Line,
  LineChart,
  XAxis,
  YAxis,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"
import { fontSize, palette, useTheme } from "@/components/ui/theme"

const MONTHS = [
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sep",
  "Oct",
]

const chartData = [
  82.4, 81.6, 81.9, 80.8, 80.1, 79.6, 79.8, 78.9, 78.4, 77.9,
].map((weight, index) => ({ month: MONTHS[index] ?? "", weight }))

const chartConfig = {
  weight: { label: "Weight", color: "purple-500" },
} satisfies ChartConfig

const styles = StyleSheet.create({
  header: { gap: 2 },
  eyebrow: { ...fontSize.sm, fontWeight: "600" },
  reading: { flexDirection: "row", alignItems: "baseline", gap: 4 },
  value: {
    ...fontSize["3xl"],
    fontWeight: "600",
    letterSpacing: -0.75,
    fontVariant: ["tabular-nums"],
  },
  unit: { ...fontSize.base, fontWeight: "600" },
  caption: { ...fontSize.sm },
  strong: { fontWeight: "600", fontVariant: ["tabular-nums"] },
  chart: { height: 160 },
})

export function LineChartDots() {
  const { colors } = useTheme()
  return (
    <Card variant="filled" size="sm">
      <CardHeader style={styles.header}>
        <Text style={[styles.eyebrow, { color: palette.purple500 }]}>
          Weight
        </Text>
        <View style={styles.reading}>
          <Text style={styles.value}>77.9</Text>
          <Text style={[styles.unit, { color: colors.mutedForeground }]}>
            kg
          </Text>
        </View>
        <Text style={[styles.caption, { color: colors.mutedForeground }]}>
          Down 4.5 kg since January
        </Text>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Weight"
          style={styles.chart}
        >
          <LineChart
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis dataKey="month" tickMargin={8} interval={2} />
            <YAxis
              orientation="right"
              tickMargin={6}
              width="auto"
              domain={[76, 84]}
              ticks={[76, 80, 84]}
            />
            <ChartTooltip
              content={
                <ChartTooltipContent
                  hideIndicator
                  formatter={(value) => (
                    <Text style={styles.strong}>{String(value)} kg</Text>
                  )}
                />
              }
            />
            <Line
              dataKey="weight"
              type="linear"
              strokeWidth={2}
              dot={{ r: 3.5 }}
              activeDot={{ r: 5 }}
            />
          </LineChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

3. Update the import paths to match your project.

**SwiftUI**

1. Target iOS 17 or later.

2. Copy the theme files every view uses:

- `swift/Theme/Theme.swift`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/swiftui/Sources/EsuissUI/Theme/Theme.swift)

- `swift/Theme/Tokens.swift`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/swiftui/Sources/EsuissUI/Theme/Tokens.swift)

3. Copy the source and every file it uses:

- `swift/Charts/LineChartDots.swift`: shown above

- `swift/Components/Card.swift`: see [Card](https://ui.suiss.app/docs/components/card.md)

- `swift/Components/Chart.swift`: see [Chart](https://ui.suiss.app/docs/components/chart.md)

- `swift/Components/Haptics.swift`: see [Haptics](https://ui.suiss.app/docs/components/haptics.md)

- `swift/Components/Item.swift`: see [Item](https://ui.suiss.app/docs/components/item.md)

- `swift/Components/Separator.swift`: see [Separator](https://ui.suiss.app/docs/components/separator.md)

- `swift/Components/TextVariant.swift`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/swiftui/Sources/EsuissUI/Components/TextVariant.swift)

4. Add the files to your app target.

**Jetpack Compose**

1. Set `minSdk` to 24 or higher and add the dependencies:

```kotlin title="build.gradle.kts"
implementation(platform("androidx.compose:compose-bom:2026.09.00"))
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.ui:ui")
```

2. Copy the theme files every view uses:

- `kotlin/theme/Theme.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/theme/Theme.kt)

- `kotlin/theme/Tokens.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/theme/Tokens.kt)

3. Copy the source and every file it uses:

- `kotlin/charts/LineChartDots.kt`: shown above

- `kotlin/components/Card.kt`: see [Card](https://ui.suiss.app/docs/components/card.md)

- `kotlin/components/Chart.kt`: see [Chart](https://ui.suiss.app/docs/components/chart.md)

- `kotlin/components/Content.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/components/Content.kt)

- `kotlin/components/FormSupport.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/components/FormSupport.kt)

- `kotlin/components/Haptics.kt`: see [Haptics](https://ui.suiss.app/docs/components/haptics.md)

- `kotlin/components/Icon.kt`: see [Icon](https://ui.suiss.app/docs/components/icon.md)

4. Update the `com.esuiss.ui` package names to match your project.

## Usage

```tsx
import { LineChartDots } from "@/components/charts/line-chart-dots"
```

```tsx
<LineChartDots />
```

Replace the weight array in `chartData` and update the header text to match. Adjust the `YAxis` `domain` and `ticks` for your range. The component takes no props.

