How to Build a Share Sheet in SwiftUI
Use ShareLink — a built-in SwiftUI view — to present the native iOS share sheet. Pass any Transferable value (String, URL, Image, or your own type) as the item parameter and SwiftUI handles the rest.
import SwiftUI
struct ContentView: View {
let url = URL(string: "https://soarias.com")!
var body: some View {
ShareLink(item: url) {
Label("Share Soarias", systemImage: "square.and.arrow.up")
}
}
}
Full implementation
ShareLink was introduced in iOS 16 and significantly improved in iOS 17 with better Transferable support and preview customisation. The example below demonstrates sharing a URL, a plain string, and a custom subject line — all the options you'll reach for in a real app. A SharePreview is included so the share sheet shows a rich title and icon instead of a raw URL.
import SwiftUI
// MARK: - Main view demonstrating three common share patterns
struct ShareSheetDemoView: View {
// 1. A URL to share
private let articleURL = URL(string: "https://soarias.com/swiftui/how-to-build-share-sheet/")!
// 2. A plain string message
private let message = "Check out this SwiftUI share-sheet guide on Soarias!"
// 3. Subject line for email / Notes clients that support it
private let subject = "SwiftUI Share Sheet Guide"
var body: some View {
NavigationStack {
List {
// — Pattern 1: Share a URL with a rich preview —
Section("Share a URL") {
ShareLink(
item: articleURL,
preview: SharePreview(
subject,
image: Image(systemName: "safari")
)
) {
Label("Share article link", systemImage: "link")
}
}
// — Pattern 2: Share plain text —
Section("Share text") {
ShareLink(item: message) {
Label("Share a message", systemImage: "text.bubble")
}
}
// — Pattern 3: Share URL + subject (great for email) —
Section("Share with subject") {
ShareLink(
item: articleURL,
subject: Text(subject),
message: Text(message)
) {
Label("Share with subject line", systemImage: "envelope")
}
}
// — Pattern 4: Fully custom button appearance —
Section("Custom button") {
ShareLink(item: articleURL) {
HStack {
Image(systemName: "square.and.arrow.up.circle.fill")
.font(.title2)
.foregroundStyle(.blue)
VStack(alignment: .leading) {
Text("Share this guide")
.font(.headline)
Text("Tap to open the share sheet")
.font(.caption)
.foregroundStyle(.secondary)
}
}
.padding(.vertical, 4)
}
.accessibilityLabel("Share the SwiftUI share sheet guide")
}
}
.navigationTitle("Share Sheet Examples")
}
}
}
#Preview {
ShareSheetDemoView()
}
How it works
-
ShareLink is a button, not a modifier. You place it directly in your view hierarchy like any other SwiftUI control. When tapped, it internally calls
UIActivityViewControllerand presents the native iOS share sheet — no.sheetor state boolean required. -
The
itemparameter accepts anyTransferablevalue. BothStringandURLalready conform toTransferableout of the box, so you can pass them directly without any extra conformances. -
SharePreviewenriches the sheet header. Thepreview:parameter (Pattern 1 above) supplies the title and thumbnail shown at the top of the share sheet, making it feel polished rather than showing a raw URL string. -
subject:andmessage:pre-fill email / notes clients. Apps that support a subject field (Mail, Notes, Reminders) will automatically populate it — your users don't have to type a title manually. -
The label closure gives you full design control. Any SwiftUI view works as the button label — an
HStack, a plainText, anImage, or a complex card layout. The share-sheet trigger is completely decoupled from its visual appearance.
Variants
Share an image from the asset catalog
import SwiftUI
struct ShareImageView: View {
// Image must be in the asset catalog or created programmatically
private let photo = Image("app-screenshot")
var body: some View {
// ShareLink works with SwiftUI Image via Transferable
ShareLink(
item: photo,
preview: SharePreview(
"App Screenshot",
image: photo
)
) {
Label("Share screenshot", systemImage: "photo")
}
}
}
#Preview {
ShareImageView()
.padding()
}
Share a list of multiple items
To share several items at once (e.g., multiple URLs or strings), use ShareLink(items:) with an array. Each item must conform to Transferable. The system combines them into a single share activity so the user is prompted only once:
let urls: [URL] = [
URL(string: "https://soarias.com")!,
URL(string: "https://developer.apple.com/xcode/swiftui/")!
]
ShareLink(items: urls) {
Label("Share \(urls.count) links", systemImage: "square.and.arrow.up.on.square")
}
Common pitfalls
-
iOS 16 vs 17 differences:
ShareLinkshipped in iOS 16, but theitems:(plural) overload and improvedTransferablecoercions arrived in iOS 16.1+. If your deployment target is iOS 16.0 exactly, test the array variant on a physical device — the simulator may behave differently. -
SwiftUI
Imagesharing requires the correct representation: Passing a SwiftUIImageasset directly works only because Apple added aTransferableconformance. If you're sharing aUIImageorCGImage, you must bridge it explicitly — wrap it in a customTransferablestruct or convert to aDatarepresentation before passing. -
Accessibility:
ShareLinkis accessible by default when you useLabel— VoiceOver reads both the icon description and the label text. If you replace the label with a purely visual button (e.g., a custom icon with no text), always add.accessibilityLabel("Share …")so VoiceOver users know what will be shared.
Prompt this with Claude Code
When using Soarias or Claude Code directly to implement this:
Implement a share sheet in SwiftUI for iOS 17+. Use ShareLink with a SharePreview for rich share-sheet headers. Support sharing a URL, a plain String, and a subject line. Make it accessible (VoiceOver labels on all ShareLink buttons). Add a #Preview with realistic sample data (real-looking URL and message text).
In the Soarias Build phase, drop this prompt into the feature file for your share flow — Claude Code will scaffold the ShareLink call, wire it to your data model, and add VoiceOver labels in one pass.
Related
FAQ
Does this work on iOS 16?
Yes — ShareLink was introduced in iOS 16 / SwiftUI 4. However, some overloads (particularly items: for sharing arrays) landed in iOS 16.1. The examples on this page target iOS 17+ and use APIs available across all iOS 17 devices. If you need iOS 16.0 compatibility, stick to the single-item: overloads and test thoroughly.
How do I share a custom data type (e.g., a struct)?
Conform your type to the Transferable protocol and implement the static transferRepresentation property. Use CodableRepresentation for JSON-serialisable structs, DataRepresentation for raw bytes, or FileRepresentation when you need to share a file on disk. Once your type conforms, pass it directly to ShareLink(item:).
What's the UIKit equivalent?
In UIKit you'd instantiate UIActivityViewController(activityItems:applicationActivities:), set its popoverPresentationController?.sourceView on iPad, then call present(_:animated:). ShareLink wraps all of that — including the iPad popover anchoring — automatically, which is why the SwiftUI version is dramatically less code.
Last reviewed: 2026-05-11 by the Soarias team.