Skip to content

Styling Custom Views Through the Environment (SwiftUI)

A SwiftUI guide for coding agents. Also covers custom style protocol, environmentkey style, share style view hierarchy, chart style struct, buttonstyle app wide, theme custom component.

System views share their styles through the environment: one .buttonStyle or .listStyle on the root view styles the whole app, and any subtree can override it. Custom views get the same power by storing a style struct in a custom EnvironmentKey.

Extract a Style Struct

Move presentation parameters out of the view's initializer into one struct with defaults, so data and appearance stop mixing in every call site.

public struct ChartStyle {
  let showAxis: Bool
  let showLabels: Bool
  let labelCount: Int?
  let showLegends: Bool

  public init(showAxis: Bool = true,
              showLabels: Bool = true,
              labelCount: Int? = nil,
              showLegends: Bool = true) {
    self.showAxis = showAxis
    self.showLabels = showLabels
    self.labelCount = labelCount
    self.showLegends = showLegends
  }
}

Put the Style in the Environment

An EnvironmentKey holds the default, an EnvironmentValues accessor exposes it, and a View extension gives callers the same modifier ergonomics as the built-in styles.

struct ChartStyleEnvironmentKey: EnvironmentKey {
  static var defaultValue: ChartStyle = .init()
}

extension EnvironmentValues {
  var chartStyle: ChartStyle {
    get { self[ChartStyleEnvironmentKey.self] }
    set { self[ChartStyleEnvironmentKey.self] = newValue }
  }
}

extension View {
  func chartStyle(_ style: ChartStyle) -> some View {
    environment(\.chartStyle, style)
  }
}

Read It in the View

The view reads the style with @Environment instead of taking it as a parameter. One modifier on a container now styles every chart inside it, and a subtree can still override.

public struct BarChartView: View {
  @Environment(\.chartStyle) var chartStyle
  let dataPoints: [DataPoint]

  var body: some View {
    // draw bars
    if chartStyle.showLabels { /* labels */ }
    if chartStyle.showLegends { /* legend */ }
  }
}

HStack {
  BarChartView(dataPoints: dataPoints1)
  BarChartView(dataPoints: dataPoints2)
}
.chartStyle(ChartStyle(showAxis: false, labelCount: 3))

This mirrors how ButtonStyle works: define makeBody(configuration:) in a struct, apply it once at the root, and every descendant picks it up.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-styling-custom-swiftui-views-using-environment" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems