
API documentation available here
Placard is a small and easy to use package for presenting an animated message bar using SwiftUI.
Message views can be displayed at the top, bottom, or center of the screen and can be offset from both the screen edges and the vertical placements using UIEdgeInsets.
There are interactive show, tap, and dismiss gestures - an array of animated themes to choose from (or no animation if you want).
Placard allows you to choose default message themes for things such as priority-based messages, but also offers customization via either parameters, a configuration object, or you can use your own SwiftUI view and let Placard control its animations and appearance. The Placard can be configured to display for any period of time (by default, it displays forever - or until a user taps on it). Further, all Placard messages can given an action to perform on user tap (but not if Placard dismisses itself via a timeout).
Placards automatically redraw themselves, adapting to device orientation changes:



Placard is built and tested for iOS 17.2 and onward only.
The PlacardDemo app allows you to explore Placard, both the default options and by changing the configuration:
Download the zip of this repository and extract it. Run PlacardDemo.xcodeproj and choose either iphone or ipad as targets for the simulator (see Requirements section for required xcode builds).
The images of Placard in this documentation were all taken as screen grabs from the PlacardDemo project.
To play with Placard via the demo interface, see the section above. But if you want to use Placard in your own projects, download Placard either via the Swift Package Manager or manually:
Go to File | Swift Packages | Add Package Dependency... in Xcode and search for "Placard".
Get Placard from the Swift Package Index
Using Placard is straight forward, but it helps to know that Placard is composed of three views that you can use:
- PlacardPriorityView: a simple, built-in way to display status messages based on priorities.
- PlacardView: Another built-in type, but more configurable than PlacardPriorityView and without priorities.
- PlacardCustomView: Placard will take your SwiftUI view and display it as a Placard!
Placard types take a configuration of type PlacardConfig that you can use to alter the behavior, placement, and formatting of a Placard view. A configuration is not necessary, but allows you to customize your Placards.
The protocol for a Placard configuration is PlacardConfigP:
public protocol PlacardConfigP {
var backgroundColor: UIColor? { get }
var primaryFont: UIFont? { get }
var secondaryFont: UIFont? { get }
var accentColor: UIColor? { get }
var titleTextColor: UIColor? { get }
var placement: PlacardPlacement? { get }
var insets: UIEdgeInsets? { get }
var showAnimation: TransitionAnimation? { get }
var hideAnimation: TransitionAnimation? { get }
var tapAnimation: TapAnimation? { get }
var fadeAnimation: Bool? { get }
}
Here is a description of those properties:
Configuration Property | Description |
---|---|
backgroundColor | Background color (as a UIColor) for the Placard view |
primaryFont | The font for the title |
secondaryFont | The font for the status message |
accentColor | Accent color (as a UIColor) for the Placard view (used for the status message foreground) |
titleTextColor | Color (as a UIColor) used for the Placard view title and systemImage foreground colors |
placement | Where to position the Placard view on the device screen |
insets | UIEdgeInsets used to offset a Placard view from its PlacardPlacement |
showAnimation | The animation to be used when the Placard view appears |
hideAnimation | The animation to be used when the Placard view disappears |
tapAnimation | The animation to be used when the Placard view is tapped by the user |
fadeAnimation | When true, the show and hide animations will fade in or out, respectively |
In the example below, all available configuration options are being set:
let config = PlacardConfig(backgroundColor: .darkGray,
primaryFont: UIFont.systemFont(ofSize: 30.0, weight: .heavy),
secondaryFont: UIFont.systemFont(ofSize: 16.0, weight: .regular),
accentColor: .red,
titleTextColor: .yellow,
placement: .top,
insets: UIEdgeInsets(top: 50, left: 20, bottom: 0, right: 20),
showAnimation: .spin,
hideAnimation: .fade,
tapAnimation: .pulseIn,
fadeAnimation: true)
Two of these properties, Insets and Animations, require a bit more elaboration:
UIEdgeInsets used to offset a Placard view from its PlacardPlacement. Keep in mind that UIEdgeInsets.left and UIEdgeInsets.right act to "push" the Placard view away from the edges of the device screen (allowing the user to create a Placard that does not span the screen). Also, all values should be positive offsets - a value for UIEdgeInsets.top of 50 will push a Placard view 50 points from the top of the device (regardless of its orientation). A value for UIEdgeInsets.bottom of 50 will push a Placard view 50 points from the bottom of the device (toward the center).
Note that for:
- PlacardPlacement.top - UIEdgeInsets.bottom is ignored
- PlacardPlacement.bottom - UIEdgeInsets.top is ignored
These are the types of the animated transitions that occur on show and hide of placard. The available options are:
public enum TransitionAnimation {
case none, fade, rollUp, rollDown, floatUp, floatDown, floatLeft, floatRight, toX, toY, toPoint, spin, spinOnX, spinOnY
}








These are the animations that occur when a user taps on placard (follow by action completion and dismissal of the Placard). The available options are:
public enum TapAnimation {
case none, pulseIn, pulseOut, zoomInWithEasing, zoomOutWithEasing
}
Its a bit difficult to see the differences via animated gifs, but play with the PlacardDemo app to see these more clearly.
Zoom out, ease in:

Zoom in, ease out:

Pulse out:

Pulse in:

Another way to use a configuration - use an enumeration. This is basically the same as using a PlacardConfig instance, but you can define a configuration type (conforming to PlacardConfigP) and pass that in instead.
enum Custom: PlacardConfigP {
// the type we are defining
case terminal
var backgroundColor: UIColor? {
switch self { case .terminal: return .lightGray }
}
var accentColor: UIColor? {
switch self {
case .terminal: return .purple
}
}
var primaryFont: UIFont? {
switch self {
case .terminal: return UIFont(name: "HelveticaNeue-Light", size: 24.0)
}
}
var secondaryFont: UIFont? {
switch self {
case .terminal: return UIFont(name: "HelveticaNeue-Light", size: 16.0)
}
}
var titleTextColor: UIColor? {
switch self { case .terminal: return .green }
}
var placement: PlacardPlacement? {
switch self { default: return .center }
}
var insets: UIEdgeInsets? {
switch self { default: return UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20) }
}
var showAnimation: TransitionAnimation? {
switch self { default: return .spinOnX }
}
var hideAnimation: TransitionAnimation? {
switch self { default: return .spinOnY }
}
var tapAnimation: TapAnimation? {
switch self { default: return .zoomOutWithEasing }
}
var fadeAnimation: Bool? {
switch self { default: return true }
}
}
It would be used like this:
PlacardView(
title: "You Dawg!",
statusMessage: "Git that squeaky!",
systemImageName: "pawprint",
config: Custom.terminal
)
PlacardPriorityView types are built-in Placards that are intended to be used for priority-based user status messages. You can alter the tile and body of the message, as well as the image via PlacardPriorityView's parameters. You can also pass in your own configuration to change a bunch more (see the configuration section above). But these are meant to be quick and easy representations of status.
You can alter any of the following parameters, but only title and statusMessage are required.
Parameter | Type | Description |
---|---|---|
title | String | Title of the Placard |
statusMessage | String | Status message of the Placard |
systemImageName | String | Name of the system image (SF Symbol) to use as an icon |
config | PlacardConfig | A configuration file (see the section above) |
duration | Double | Number of seconds for the Placard to display |
action | () -> Void | An action to execute on Placard being tapped by user |
priority | PlacardPriority | .success, .info, .warning, .error, or a .default priority |
Here, we create a success message with our own title and status message:
PlacardPriorityView(title: "Success!",
statusMessage: "Some status message",
priority: .success)

The PlacardView type is similar to the PlacardPriorityView type, but has no priority associated with it. It can be customized in the same ways.
Its available set of parameters is:
Parameter | Type | Description |
---|---|---|
title | String | Title of the Placard |
statusMessage | String | Status message of the Placard |
systemImageName | String | Name of the system image (SF Symbol) to use as an icon |
config | PlacardConfig | A configuration file (see the section above) |
duration | Double | Number of seconds for the Placard to display |
action | () -> Void | An action to execute on Placard being tapped by user |
Here, we pass in our own systemImage to display:
PlacardView(title: "Don't forget to smile!",
statusMessage: "Teeth are like bats that hang from your gums.",
systemImageName: "mouth.fill")
Placards take an action (of type () -> Void) to perform when tapped (ONLY if tapped - if you set a duration and the Placard expires before a user taps it, the action will not be fired).
PlacardView(title: "Don't forget to smile!",
statusMessage: "Teeth are like bats that hang from your gums.",
systemImageName: "face.smiling",
action: { print("You tapped me!") })

When you want to provide your own SwiftUI views while using Placard's functionality, you will use the PlacardCustomView.
The set of available parameters for a PlacardCustomView is:
Parameter | Type | Description |
---|---|---|
title | String | Title of the Placard |
statusMessage | String | Status message of the Placard |
content | UIView | Your SwiftUI view |
config | PlacardConfig | A configuration file (see the section above) |
duration | Double | Number of seconds for the Placard to display |
action | () -> Void | An action to execute on Placard being tapped by user |
Define your own SwiftUI view to use as a Placard. Here is an example:
struct ViewWithButton: View {
@State var action: Bool
var body: some View {
var color: String {
if action { return "red" }
return "green"
}
VStack {
Text("Make me see \\(color)")
.background(action ? .green : .red)
Button(action: {
action.toggle()
}) {
HStack {
Image(systemName: "face.dashed")
.font(.title)
.foregroundColor(action ? .green : .red)
Text("change me")
.fontWeight(.semibold)
.font(.title)
}
.padding()
.foregroundColor(.white)
.background(Color.black)
.cornerRadius(40)
}
}
.frame(maxWidth: .infinity, minHeight: 200, alignment: .center)
.background(Color(red: 155/255, green: 198/255, blue: 222/255))
}
}
Pass that view into a PlacardCustomView instance:
PlacardCustomView(title: "some title", statusMessage: "some body", config: custom_config) {
// SwiftUI view
ViewWithButton(action: toggle)
}
