How to Create IBDesignable UI Components in iOS: Live Rendering Guide

Create custom UI components with live rendering in Xcode 26's Interface Builder using @IBDesignable on the class declaration and @IBInspectable on individual properties.

Understanding @IBDesignable and @IBInspectable

@IBDesignable tells Xcode to render the custom view on the storyboard canvas in real time. @IBInspectable exposes a property in the Attributes inspector for visual configuration.

Interface Builder supports these @IBInspectable property types: Int, CGFloat, Double, String, Bool, CGPoint, CGSize, CGRect, UIColor, and UIImage. Any other type is silently ignored by Interface Builder.

Building a Custom Button with @IBDesignable

Start by subclassing UIButton and marking the class with @IBDesignable:

@IBDesignable
class DesignableButton: UIButton {
}

Adding Corner Radius, Border Width, and Border Color

Add @IBInspectable properties for the three most common button customizations:

@IBDesignable
class DesignableButton: UIButton {
    @IBInspectable var cornerRadius: CGFloat = 0.0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }

    @IBInspectable var borderWidth: CGFloat = 0.0 {
        didSet { layer.borderWidth = borderWidth }
    }

    @IBInspectable var borderColor: UIColor = .black {
        didSet { layer.borderColor = borderColor.cgColor }
    }
}

Set a UIButton's custom class to DesignableButton in the Identity inspector. Open the Attributes inspector to find Corner Radius, Border Width, and Border Color fields under a Designable Button section. Changing these values updates the canvas immediately.

Adding Right-Aligned Image Support

UIButton places the image on the left by default. Override layoutSubviews to reposition the image to the right side:

@IBInspectable var imageOnRight: Bool = false
@IBInspectable var imagePadding: CGFloat = 0.0

override func layoutSubviews() {
    super.layoutSubviews()

    if imageOnRight, let imageView = imageView {
        imageEdgeInsets.left = bounds.width - imageView.bounds.width - imagePadding
    }
}

The imageOnRight boolean appears as a toggle switch in the Attributes inspector. The formula pushes the image to the right edge minus the padding value.

Adding a Gradient Background

CAGradientLayer creates smooth color transitions. Add inspectable properties for gradient colors:

@IBInspectable var enableGradient: Bool = false
@IBInspectable var gradientStartColor: UIColor = .black
@IBInspectable var gradientEndColor: UIColor = .white

override func layoutSubviews() {
    super.layoutSubviews()

    if enableGradient {
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        gradientLayer.colors = [gradientStartColor.cgColor, gradientEndColor.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        layer.insertSublayer(gradientLayer, at: 0)
    }
}

Change startPoint and endPoint to control gradient direction. A horizontal gradient uses (0.0, 0.5) to (1.0, 0.5). A vertical gradient uses (0.5, 0.0) to (0.5, 1.0).

Adding Shadow Properties

Add inspectable shadow properties for depth effects on buttons and cards:

@IBInspectable var shadowOpacity: Float = 0.0 {
    didSet { layer.shadowOpacity = shadowOpacity }
}

@IBInspectable var shadowRadius: CGFloat = 0.0 {
    didSet { layer.shadowRadius = shadowRadius }
}

@IBInspectable var shadowOffset: CGSize = CGSize(width: 0, height: 2) {
    didSet { layer.shadowOffset = shadowOffset }
}

@IBInspectable var shadowColor: UIColor = .black {
    didSet { layer.shadowColor = shadowColor.cgColor }
}

Set shadowOpacity to a non-zero value to make the shadow visible. Combine shadowRadius with shadowOffset for a natural drop-shadow effect. Shadows render live on the Interface Builder canvas.

Using @IBDesignable with UIView Subclasses

@IBDesignable works with any UIView subclass, not just UIButton. Create a custom card view with inspectable properties:

@IBDesignable
class DesignableCardView: UIView {
    @IBInspectable var cornerRadius: CGFloat = 0.0 {
        didSet { layer.cornerRadius = cornerRadius }
    }

    @IBInspectable var borderWidth: CGFloat = 0.0 {
        didSet { layer.borderWidth = borderWidth }
    }
}

Apply this class to any UIView in the storyboard. The corner radius and border width properties appear in the Attributes inspector.

Using the Custom Button in Interface Builder

Drop a UIButton on the storyboard. Set its class to DesignableButton in the Identity inspector. Configure all properties in the Attributes inspector under the Designable Button section.

A Sign-In button with rounded corners requires setting cornerRadius to 8 and enabling a gradient. An outlined button requires setting borderWidth to 2 and borderColor to a brand color. Each configuration uses the same DesignableButton class with different property values.

Inspectable Property Display Names

Xcode automatically converts camelCase property names to human-readable names in the Attributes inspector. The cornerRadius property appears as Corner Radius. The borderColor property appears as Border Color. The shadowOpacity property appears as Shadow Opacity.

When to Use @IBDesignable

Use @IBDesignable for design system components that require visual consistency across multiple screens. Use @IBInspectable for buttons, cards, and input fields that need brand-specific styling. Use both together for rapid prototyping where designers need to experiment with colors and sizes without writing code.

Avoid @IBDesignable for complex layout logic or views with expensive drawing code. Interface Builder renders designable views in a separate process. Heavy computations cause slow performance or rendering errors.

Performance Considerations

Xcode runs @IBDesignable code in a separate process for live preview. Keep layoutSubviews and draw methods lightweight. Create layers, set frames, and apply colors. Do not perform network requests, file I/O, or heavy calculations in designable code.

If Interface Builder displays a Drawing error message, simplify the layoutSubviews implementation. Remove any asynchronous operations or expensive computations.

Summary

This tutorial covered the complete implementation process from setup to working code. You now have a functional implementation that you can extend and customize for your own projects. The same patterns apply to related features in the iOS ecosystem.

Frequently Asked Questions

What Xcode version do I need for this tutorial? This tutorial uses Xcode 26 with Swift 6.2. The code examples work with any recent version of Xcode that supports the frameworks used here.

What are the prerequisites for this tutorial? You need Xcode installed on a Mac and basic familiarity with Swift programming. No prior experience with the specific framework is required.

All articles