If you create the Slider using an initializer that doesn't add labels, then a simple way to add tick marks is to show them in an HStack in the background behind the Slider, with a Spacer between each one.
The only complication is that the slider button stops with its edge aligned with the edge of the slider groove, it does not go over the end of the groove. So it is necessary to add horizontal padding to the HStack, equivalent to half the width of the slider button.
If the tick marks are given a width of 2 points, it works quite well to use horizontal padding of 12:
Slider(value: $value, in: 5...20, step: 5)
.frame(maxWidth: 300)
.background {
HStack {
ForEach(0..<4) { i in
Color.pink
.frame(width: 2)
.padding(.vertical, 5)
if i < 3 {
Spacer()
}
}
}
.padding(.horizontal, 12)
}

EDIT If you don't like hard-coding the width of the padding, you could use .onGeometryChange to measure the height of the slider. The height of the slider is determined by the thumb size + shadow, so this gives a reasonable approximation of the thumb diameter. You could make it more accurate by subtracting a few points for the shadow, but that would be using hard-coded values again. It works quite well even without the shadow correction:
@State private var thumbSize = CGFloat.zero
Slider(value: $value, in: 5...20, step: 5)
.frame(maxWidth: 300)
.background {
HStack {
// ... as above
}
.padding(.horizontal, thumbSize / 2)
}
.onGeometryChange(for: CGFloat.self) { proxy in
proxy.size.height
} action: { height in
thumbSize = height
}
If you need to label the slider range, you can always put the Slider inside an HStack and place your own min and max labels before and after the Slider. Alternatively, you can label each of the ticks. For ways of aligning labels with the tick marks, see the answer to How to space out varying width text in HStack so centre of the text is positioned correctly in SwiftUI.