# Bar Chart Hourly

Twenty-four thin bars of screen time per hour, with a dashed line marking the hourly average.

Bar Chart Hourly 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/bar-chart-hourly

**React**

**Example**

```tsx title="components/charts/bar-chart-hourly.tsx"
"use client"

import {
  Bar,
  BarChart,
  CartesianGrid,
  ReferenceLine,
  XAxis,
  YAxis,
} from "recharts"

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

const chartData = [
  4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42,
  47, 35, 18,
].map((minutes, hour) => ({ hour, minutes }))

const chartConfig = {
  minutes: { label: "Screen time", color: "var(--chart-1)" },
} satisfies ChartConfig

const total = chartData.reduce((sum, item) => sum + item.minutes, 0)
const average = total / chartData.length

export function BarChartHourly() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <p className="text-sm font-semibold text-primary">Screen time</p>
        <p className="text-3xl font-semibold tracking-tight tabular-nums">
          {Math.floor(total / 60)}h {total % 60}m
        </p>
        <p className="text-sm text-muted-foreground">Today · hour by hour</p>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-40 w-full"
        >
          <BarChart
            accessibilityLayer
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="hour"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              ticks={[0, 6, 12, 18]}
              interval={0}
              tickFormatter={(value: number) => `${value}:00`}
            />
            <YAxis
              orientation="right"
              tickLine={false}
              axisLine={false}
              tickMargin={6}
              width="auto"
              tickCount={3}
              tickFormatter={(value: number) => `${value} min`}
            />
            <ReferenceLine
              y={average}
              stroke="var(--color-green-500)"
              strokeDasharray="3 3"
            />
            <ChartTooltip
              cursor={false}
              content={
                <ChartTooltipContent
                  hideIndicator
                  labelFormatter={(_, payload) =>
                    `${payload[0]?.payload.hour}:00`
                  }
                  formatter={(value) => (
                    <span className="font-semibold tabular-nums">
                      {value} min
                    </span>
                  )}
                />
              }
            />
            <Bar
              dataKey="minutes"
              fill="var(--color-minutes)"
              radius={[3, 3, 0, 0]}
              maxBarSize={8}
            />
          </BarChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

A screen-time card with 24 thin hourly bars, a total in the header and a dashed line at the hourly average. Use it for any day-at-a-glance metric with many small periods.

## Installation

### CLI

```bash title="Terminal"
npx shadcn@latest add @esuiss/bar-chart-hourly
```

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 bar-chart-hourly
```

### 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/bar-chart-hourly.tsx`:

```tsx title="components/charts/bar-chart-hourly.tsx"
"use client"

import {
  Bar,
  BarChart,
  CartesianGrid,
  ReferenceLine,
  XAxis,
  YAxis,
} from "recharts"

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

const chartData = [
  4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42,
  47, 35, 18,
].map((minutes, hour) => ({ hour, minutes }))

const chartConfig = {
  minutes: { label: "Screen time", color: "var(--chart-1)" },
} satisfies ChartConfig

const total = chartData.reduce((sum, item) => sum + item.minutes, 0)
const average = total / chartData.length

export function BarChartHourly() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <p className="text-sm font-semibold text-primary">Screen time</p>
        <p className="text-3xl font-semibold tracking-tight tabular-nums">
          {Math.floor(total / 60)}h {total % 60}m
        </p>
        <p className="text-sm text-muted-foreground">Today · hour by hour</p>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-40 w-full"
        >
          <BarChart
            accessibilityLayer
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="hour"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              ticks={[0, 6, 12, 18]}
              interval={0}
              tickFormatter={(value: number) => `${value}:00`}
            />
            <YAxis
              orientation="right"
              tickLine={false}
              axisLine={false}
              tickMargin={6}
              width="auto"
              tickCount={3}
              tickFormatter={(value: number) => `${value} min`}
            />
            <ReferenceLine
              y={average}
              stroke="var(--color-green-500)"
              strokeDasharray="3 3"
            />
            <ChartTooltip
              cursor={false}
              content={
                <ChartTooltipContent
                  hideIndicator
                  labelFormatter={(_, payload) =>
                    `${payload[0]?.payload.hour}:00`
                  }
                  formatter={(value) => (
                    <span className="font-semibold tabular-nums">
                      {value} min
                    </span>
                  )}
                />
              }
            />
            <Bar
              dataKey="minutes"
              fill="var(--color-minutes)"
              radius={[3, 3, 0, 0]}
              maxBarSize={8}
            />
          </BarChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

4. Update the import paths to match your project.

## Usage

```tsx
import { BarChartHourly } from "@/components/charts/bar-chart-hourly"
```

```tsx
<BarChartHourly />
```

Replace the 24 values in `chartData` with your own per-hour numbers; the total and the average line are computed from them. Change the axis `ticks` to label different hours, and update the minute unit in the axis, tooltip and header if you measure something else.

## Notes

With 24 narrow bars, the tooltip is the most reliable way to read a single hour. Focus the chart and use the arrow keys to step through the hours.

**React Native, SwiftUI, Jetpack Compose**

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

```tsx title="uniwind/components/charts/bar-chart-hourly.tsx"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  Bar,
  BarChart,
  CartesianGrid,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  ReferenceLine,
  XAxis,
  YAxis,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"

const chartData = [
  4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42,
  47, 35, 18,
].map((minutes, hour) => ({ hour, minutes }))

const chartConfig = {
  minutes: { label: "Screen time", color: "chart-1" },
} satisfies ChartConfig

const total = chartData.reduce((sum, item) => sum + item.minutes, 0)
const average = total / chartData.length

export function BarChartHourly() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <Text className="text-sm font-semibold text-primary">Screen time</Text>
        <Text className="text-3xl font-semibold tracking-tight tabular-nums">
          {`${Math.floor(total / 60)}h ${total % 60}m`}
        </Text>
        <Text className="text-sm text-muted-foreground">
          Today · hour by hour
        </Text>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Screen time"
          className="h-40 w-full"
        >
          <BarChart
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="hour"
              tickMargin={8}
              ticks={[0, 6, 12, 18]}
              interval={0}
              tickFormatter={(value) => `${value}:00`}
            />
            <YAxis
              orientation="right"
              tickMargin={6}
              width="auto"
              tickCount={3}
              tickFormatter={(value) => `${value} min`}
            />
            <ReferenceLine
              y={average}
              stroke="green-500"
              strokeDasharray="3 3"
            />
            <ChartTooltip
              cursor={false}
              content={
                <ChartTooltipContent
                  hideIndicator
                  labelFormatter={(_, payload) =>
                    `${String(payload[0]?.payload.hour)}:00`
                  }
                  formatter={(value) => (
                    <Text className="font-semibold tabular-nums">
                      {`${String(value)} min`}
                    </Text>
                  )}
                />
              }
            />
            <Bar
              dataKey="minutes"
              fill="chart-1"
              radius={[3, 3, 0, 0]}
              maxBarSize={8}
            />
          </BarChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

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

private let minutes: [Double] = [
  4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42, 47, 35, 18,
]

private let hours = minutes.indices.map { "\($0)" }

private let chartConfig: ChartConfig = [
  "minutes": .init("Screen time", color: EsuissColor.chart1),
]

private let total = Int(minutes.reduce(0, +))
private let average = minutes.reduce(0, +) / Double(minutes.count)

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

  public init() {}

  public var body: some View {
    Card(.filled, size: .sm) {
      VStack(alignment: .leading, spacing: 2) {
        Text("Screen time")
          .textStyle(.sm, weight: .semibold)
          .foregroundStyle(EsuissColor.primary)
        Text(verbatim: "\(total / 60)h \(total % 60)m")
          .textStyle(.xl3, weight: .semibold)
          .monospacedDigit()
        Text("Today · hour by hour")
          .textStyle(.sm)
          .foregroundStyle(EsuissColor.mutedForeground)
      }
      .padding(.horizontal, 16)
      CardContent {
        ChartContainer(config: chartConfig) {
          ChartAnimator(animationDuration: 400) { progress in
            Chart {
              ForEach(minutes.indices, id: \.self) { hour in
                BarMark(x: .value("Hour", hours[hour]), y: .value("Minutes", minutes[hour] * progress), width: .fixed(8))
                  .clipShape(UnevenRoundedRectangle(topLeadingRadius: 3, topTrailingRadius: 3, style: .continuous))
                  .foregroundStyle(chartConfig.color("minutes"))
                ChartAnchorMark(x: .value("Hour", hours[hour]), y: .value("Minutes", minutes[hour]))
              }
              RuleMark(y: .value("Average", average))
                .lineStyle(StrokeStyle(lineWidth: 1, dash: [3, 3]))
                .foregroundStyle(Palette.green500)
            }
            .chartXAxis { ChartAxis.x(values: ["0", "6", "12", "18"]) { "\($0):00" } }
            .chartYAxis { ChartAxis.y(count: 3) { "\(Int($0)) min" } }
            .chartTooltip(
              x: hours,
              labels: hours.map { "\($0):00" },
              selection: $selection,
              cursor: false,
              accessibilityLabel: "Screen time",
              items: { [ChartTooltipItem("minutes", value: minutes[$0])] }
            ) { payload in
              ChartTooltipContent(payload, hideIndicator: true) { payload in
                Text(verbatim: payload.label)
              } formatter: { item in
                Text("\(Int(item.value)) min")
                  .scaledFont(TextStyle.xs, weight: .semibold)
                  .monospacedDigit()
              }
            }
          }
        }
        .frame(height: 160)
      }
    }
  }
}
```

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

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.BarChart
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.ChartMargin
import com.esuiss.ui.components.ChartRadius
import com.esuiss.ui.components.ChartTooltipContent
import com.esuiss.ui.theme.EsuissTheme
import com.esuiss.ui.theme.Palette
import com.esuiss.ui.theme.Typography

private class HourMinutes(val hour: Int, val minutes: Int)

private val chartData = listOf(
    4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42, 47, 35, 18,
).mapIndexed { hour, minutes -> HourMinutes(hour, minutes) }

private val chartConfig = ChartConfig(
    "minutes" to ChartConfigItem("Screen time") { chart1 },
)

private val total = chartData.sumOf { it.minutes }

private val average = total.toDouble() / chartData.size

@Composable
fun BarChartHourly(modifier: Modifier = Modifier) {
    val colors = EsuissTheme.colors
    Card(modifier, variant = CardVariant.Filled, size = CardSize.Sm) {
        CardContent {
            Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
                BasicText("Screen time", style = Typography.sm.copy(color = colors.primary, fontWeight = FontWeight.SemiBold))
                BasicText(
                    "${total / 60}h ${total % 60}m",
                    style = Typography.xl3.copy(color = colors.foreground, fontWeight = FontWeight.SemiBold, fontFeatureSettings = "tnum"),
                )
                BasicText("Today · hour by hour", style = Typography.sm.copy(color = colors.mutedForeground))
            }
        }
        CardContent {
            ChartContainer(
                chartConfig,
                Modifier
                    .fillMaxWidth()
                    .height(160.dp),
            ) {
                BarChart(
                    chartData,
                    margin = ChartMargin(top = 10.dp, right = 4.dp, bottom = 0.dp, left = 12.dp),
                    accessibilityLabel = "Screen time",
                ) {
                    CartesianGrid(strokeDasharray = listOf(2f, 4f))
                    XAxis(label = { "${it.hour}" }, tickMargin = 8.dp, interval = 0, ticks = listOf(0, 6, 12, 18), tickFormatter = { "$it:00" })
                    YAxis(
                        orientation = ChartAxisOrientation.Right,
                        tickMargin = 6.dp,
                        tickCount = 3,
                        tickFormatter = { "${it.toInt()} min" },
                    )
                    ReferenceLine(average, stroke = Palette.green500, strokeDasharray = listOf(3f, 3f))
                    ChartTooltip(cursor = null) {
                        ChartTooltipContent(
                            hideIndicator = true,
                            labelFormatter = { label, _ ->
                                BasicText("$label:00", style = Typography.xs.copy(color = colors.foreground, fontWeight = FontWeight.SemiBold))
                            },
                            formatter = { item ->
                                BasicText(
                                    "${item.value.toInt()} min",
                                    style = Typography.xs.copy(color = colors.foreground, fontWeight = FontWeight.SemiBold, fontFeatureSettings = "tnum"),
                                )
                            },
                        )
                    }
                    Bar(
                        "minutes",
                        value = { it.minutes.toDouble() },
                        radius = ChartRadius(3.dp, 3.dp, 0.dp, 0.dp),
                        maxBarSize = 8.dp,
                    )
                }
            }
        }
    }
}
```

Thin bars show minutes for each hour of the day, with ticks every six hours and a value axis in minutes on the right. A `ReferenceLine` marks the hourly average, and the header shows the day's total in hours and minutes. The tooltip formats the hour and the minutes.

## Installation

**React Native**

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

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 bar-chart-hourly
```

**SwiftUI**

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

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add bar-chart-hourly --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/bar-chart-hourly.tsx`:

- `uniwind/components/charts/bar-chart-hourly.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/bar-chart-hourly.tsx`:

```tsx title="nativewind/components/charts/bar-chart-hourly.tsx"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  Bar,
  BarChart,
  CartesianGrid,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  ReferenceLine,
  XAxis,
  YAxis,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"

const chartData = [
  4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42,
  47, 35, 18,
].map((minutes, hour) => ({ hour, minutes }))

const chartConfig = {
  minutes: { label: "Screen time", color: "chart-1" },
} satisfies ChartConfig

const total = chartData.reduce((sum, item) => sum + item.minutes, 0)
const average = total / chartData.length

export function BarChartHourly() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader className="gap-0.5">
        <Text className="text-sm font-semibold text-primary">Screen time</Text>
        <Text className="text-3xl font-semibold tracking-tight tabular-nums">
          {`${Math.floor(total / 60)}h ${total % 60}m`}
        </Text>
        <Text className="text-sm text-muted-foreground">
          Today · hour by hour
        </Text>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Screen time"
          className="h-40 w-full"
        >
          <BarChart
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="hour"
              tickMargin={8}
              ticks={[0, 6, 12, 18]}
              interval={0}
              tickFormatter={(value) => `${value}:00`}
            />
            <YAxis
              orientation="right"
              tickMargin={6}
              width="auto"
              tickCount={3}
              tickFormatter={(value) => `${value} min`}
            />
            <ReferenceLine
              y={average}
              stroke="green-500"
              strokeDasharray="3 3"
            />
            <ChartTooltip
              cursor={false}
              content={
                <ChartTooltipContent
                  hideIndicator
                  labelFormatter={(_, payload) =>
                    `${String(payload[0]?.payload.hour)}:00`
                  }
                  formatter={(value) => (
                    <Text className="font-semibold tabular-nums">
                      {`${String(value)} min`}
                    </Text>
                  )}
                />
              }
            />
            <Bar
              dataKey="minutes"
              fill="chart-1"
              radius={[3, 3, 0, 0]}
              maxBarSize={8}
            />
          </BarChart>
        </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/bar-chart-hourly.tsx`:

```tsx title="stylesheet/components/charts/bar-chart-hourly.tsx"
import { StyleSheet } from "react-native"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import {
  Bar,
  BarChart,
  CartesianGrid,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  ReferenceLine,
  XAxis,
  YAxis,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"
import { fontSize, useTheme } from "@/components/ui/theme"

const chartData = [
  4, 0, 0, 0, 0, 0, 6, 18, 27, 22, 19, 21, 30, 26, 23, 17, 22, 26, 31, 39, 42,
  47, 35, 18,
].map((minutes, hour) => ({ hour, minutes }))

const chartConfig = {
  minutes: { label: "Screen time", color: "chart-1" },
} satisfies ChartConfig

const total = chartData.reduce((sum, item) => sum + item.minutes, 0)
const average = total / chartData.length

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

export function BarChartHourly() {
  const { colors } = useTheme()
  return (
    <Card variant="filled" size="sm">
      <CardHeader style={styles.header}>
        <Text style={[styles.eyebrow, { color: colors.primary }]}>
          Screen time
        </Text>
        <Text style={styles.value}>
          {`${Math.floor(total / 60)}h ${total % 60}m`}
        </Text>
        <Text style={[styles.caption, { color: colors.mutedForeground }]}>
          Today · hour by hour
        </Text>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Screen time"
          style={styles.chart}
        >
          <BarChart
            data={chartData}
            margin={{ top: 10, right: 4, left: 12, bottom: 0 }}
          >
            <CartesianGrid vertical={false} strokeDasharray="2 4" />
            <XAxis
              dataKey="hour"
              tickMargin={8}
              ticks={[0, 6, 12, 18]}
              interval={0}
              tickFormatter={(value) => `${value}:00`}
            />
            <YAxis
              orientation="right"
              tickMargin={6}
              width="auto"
              tickCount={3}
              tickFormatter={(value) => `${value} min`}
            />
            <ReferenceLine
              y={average}
              stroke="green-500"
              strokeDasharray="3 3"
            />
            <ChartTooltip
              cursor={false}
              content={
                <ChartTooltipContent
                  hideIndicator
                  labelFormatter={(_, payload) =>
                    `${String(payload[0]?.payload.hour)}:00`
                  }
                  formatter={(value) => (
                    <Text style={styles.strong}>{`${String(value)} min`}</Text>
                  )}
                />
              }
            />
            <Bar
              dataKey="minutes"
              fill="chart-1"
              radius={[3, 3, 0, 0]}
              maxBarSize={8}
            />
          </BarChart>
        </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/BarChartHourly.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/BarChartHourly.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 { BarChartHourly } from "@/components/charts/bar-chart-hourly"
```

```tsx
<BarChartHourly />
```

Replace the 24 values in `chartData` with your hourly minutes; the total and average are calculated from it. The component takes no props.

