I am revisiting my previous answer with this new answer, since I figured out that there is a way to change the color of the icon inside a Picker.
I stumbled upon this when I was looking at the documentation for .foregroundStyle when using primary and secondary levels:
.foregroundStyle(.blue, .orange)
Using this format on the icon inside the picker will allow it to be colored. This is because when using this initializer, it will use the .palette rendering mode for symbol images.
This means that we can also specify the .palette rendering mode and use the regular .foregroundStyle modifier to achieve the same effect (UPDATE: Turns out .tint is also needed for iOS 18.4):
Picker("Select color", selection: $selectedColor) {
ForEach(PickerColor.allCases) { option in
Label {
Text(option.rawValue.capitalized)
} icon: {
Image(systemName: "circle.fill")
.symbolRenderingMode(.palette) // <- specify .palette rendering mode
.foregroundStyle(option.color) // <- use .foregroundStyle as usual
.tint(option.color) // required for iOS 18.4
}
.tag(option)
}
}
To have the picker's label also be colored using the selected color, use the .tint modifier on the picker:
.tint(selectedColor.color)
Here's the complete code to try:
import SwiftUI
enum PickerColor: String, CaseIterable, Identifiable {
var id: String { self.rawValue }
case indigo
case red
case green
case blue
case yellow
case orange
case purple
var color: Color {
switch self {
case .indigo: return .indigo
case .red: return .red
case .green: return .green
case .blue: return .blue
case .yellow: return .yellow
case .orange: return .orange
case .purple: return .purple
}
}
}
struct PickerIconColor: View {
//State values
@State private var showMenu = false
@State private var selectedColor: PickerColor = .indigo
//Body
var body: some View {
Picker("Select color", selection: $selectedColor) {
ForEach(PickerColor.allCases) { option in
Label {
Text(option.rawValue.capitalized)
} icon: {
Image(systemName: "circle.fill")
.symbolRenderingMode(.palette)
.foregroundStyle(option.color)
.tint(option.color)
}
.tag(option)
}
}
.tint(selectedColor.color)
}
}
#Preview("PickerMenuColorAlt") {
PickerIconColor()
}

BONUS: For more control over the selected option styling, wrap the picker in a Menu with a custom label:
Menu {
Picker("Select color", selection: $selectedColor) {
ForEach(PickerColor.allCases) { option in
Label {
Text(option.rawValue.capitalized)
} icon: {
Image(systemName: "circle.fill")
.symbolRenderingMode(.palette)
.foregroundStyle(option.color)
.tint(option.color)
}
.tag(option)
}
}
} label : {
HStack {
Label {
Text(selectedColor.rawValue.capitalized)
} icon: {
Image(systemName: "circle.fill")
.foregroundStyle(selectedColor.color)
.imageScale(.small)
}
//Chevron icon to make it look like the picker
Image(systemName: "chevron.up.chevron.down")
.imageScale(.small)
}
}
.tint(selectedColor.color)

For even more control, use an HStack instead of a Label to set spacing between the icons and text.
UPDATE iOS 18.4:
For some strange reason, after updating to iOS 18.4, all icons in all menus turned the same color blue on device, while still showing multi colored in XCode Previews. After some poking, I figured out they now require both a .foregroundStyle and a .tint (set to the same color) to restore the individual color of each icon. I don't know if this is intentional or a bug.
I updated the code above to reflect this.
Looks like the change could be related to this from the iOS 18.4 release notes:
-
Fixed: A color set by the tint(_:) modifier does not override the tint color of buttons in that view’s confirmation dialogs and alerts. (138774306)