# Styling - Styling of UI components

Modern iOS applications often come with custom styling of their UI components. UIKit provides several different approaches for styling your UI. Either you set them explicitly through properties on your views, or you work indirectly with these properties using interface builder or the appearance manager. Form adds programmatic support for styling your UI using style types that allow for easier reuse and modification of your styles.

## Styles

Form supports several different kinds of styles, where some are used mainly to compose other styles. You typically pass a style when you construct your UI components:

```swift
let label = UILabel(value: "Hello", style: .header)
```

Many UI components come with default styles, so you can skip passing styles explicitly:

```swift
let label = UILabel(value: "Hello")
```

A UI component's style is often available from a mutable `style` property as well, allowing convenient updating of styling: 

```swift
label.style = .footer
label.style.color = .red
```

By using the `restyled` helper, new styles can easily be created based on existing styles:

```swift
let footStyle = TextStyle.header.restyled { style in
  style.font = ...
  style.color = ...
}
```

For commonly reused styles we recommend adding them as static extensions:

```swift
extension TextStyle {
    static let header = defaultLabel.restyled { ... }
}
```

And for common restyling, you can add helpers such as:

```swift
extension TextStyle {
  func colored(_ color: UIColor) -> TextStyle {
    return restyled { $0.color = color }
  }
}
```

Form comes with many similar helpers such as the one above allowing for a more declarative restyling:

```swift
let footer = TextStyle.header.colored(.blue).resized(to: 24)
```

## Dynamic styles

Some styles might change based on changes in the application environment such as traits changes. For these styles, there is a corresponding `DynamicStyle` that produces styles based on some dynamic properties such as `UITraitCollection`. This is true for `FormStyle` and `SectionStyle` used for styling table like views such as `UITableView`, `FormView` and `SectionView`.

Dynamic styles can also be restyled:

```swift
let customSection = DynamicSectionStyle.default.restyled { style in
  style.header.text.color = .red
}
```

And if you need to adjust differently based on the traits:

```swift
let dynamicSection = customSection.restyledWithStyleAndInput { style, traits in
  let isCompact = traits.horizontalSizeClass = .compact
  style.header.text.resized(to: isCompact ? 14 : 18)
}
```

## Default styling

Many styles and UI components have a default style that will be used when an explicit style is not passed to an initializer. By default, these defaults try to match iOS's system styling. However new defaults can be set up via the `DefaultStyling` style:

```swift
extension DefaultStyling {
  static let custom = DefaultStyling(...)
}
```

And the default styling can be updated by reassigning `defaults`:

```swift
DefaultStyling.defaults = .custom
```

You should preferably set up the defaults early on in your applications life cycle. 

If you want to support some kind of application theming by updating the defaults while the UI is presented, you have to reload the views (or update their styles explicitly). It is also important to set up your custom styles as computed properties instead of stored, so they will re-evaluate with the currently selected defaults instead of being cached.  

## Backgrounds

Several UI components such as buttons and sections use images to style their backgrounds. If you want to create these images procedurally, Form provides some helper styles such as `BackgroundStyle` and `SectionBackgroundStyle`. 

```swift
let background = BackgroundStyle(border: BorderStyle(...), color: ...) 
let image = UIImage(image: background)
```

## TextStyle

`TextStyle` supports the same styling as attributed strings. Not all attributes are exposed as convenience properties though. You can still set these using:

```swift
textStyle.setAttribute(letterSpacing, for: .kern)
```

But preferably you should add helpers instead:

```swift
extension TextStyle {
  var letterSpacing: Float {
    get { return attribute(for: .kern) ?? 0 }
    set { setAttribute(newValue, for: .kern, defaultValue: 0) }
  } 
}
```

Text styles also support registering your own custom string transformations via the `TextStyle.registerCustomTransform()`. For example, Form provides the `textCase` transformation and comes with helpers such as uppercased:

```swift
let header = TextStyle.default.uppercased
```