Pattern · Forms

New

Feedback Form SwiftUI Block

A send-feedback section: a five-step rating, topic chips, a message, screenshots, device info and a thank-you.

The send-feedback section of a Help or Settings screen. A numbered rating, Bug, Idea, Billing and Other chips that change the message's prompt, up to three screenshots from the system picker, and Include device info that lists exactly what it sends. Send checks for a topic and a message, shows its working and failed states, and a thank-you replaces the form once it lands.

  • SwiftUI
  • iOS 17.0+
  • feedback-form
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • A five-step rating from Not great to Love it
  • Topic chips that change the message's prompt
  • Up to three screenshots from the system picker, removable
  • Include device info that shows exactly what it sends
  • An optional reply email when signed out, and a thank-you with Done

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

The first card asks "How's it going?" with five numbered segments from "Not great" to "Love it"; tapping one fills it in ink, tapping it again clears it. The second asks "What's it about?" with Bug, Idea, Billing and Other as chips, and the message under them asks the question that fits the topic ("What happened, and what did you expect instead?" for a bug) with a count toward its limit. The third holds Screenshots, up to three thumbnails from the system photo picker with a remove button each and an Add tile, and Include device info, which lists exactly what it adds: app version, system, device and language. When the person is signed out an optional email for a reply follows. Send feedback checks that a topic and a message are there, then live as they're fixed, runs your closure with a spinner, and shows the thrown error's message under it if it fails. Once it lands, a thank-you replaces the form, saying where a reply would go, with Done to close.

Notes

  • FeedbackForm(topics:accountEmail:deviceDetails:messageLimit:maxScreenshots:onSend:onDone:). Only onSend is required. It is a section: no navigation stack, background, padding or scroll view of its own, so place it in your own column or sheet.
  • onSend receives a FeedbackForm.Submission: the rating (1 to 5, or nil), the chosen topic id, the trimmed message, screenshots as JPEG data at most 1600 points on the longest side in the order attached, deviceDetails when included, and replyEmail (the account's, the one typed, or nil). Return to succeed, throw to fail; a thrown LocalizedError's errorDescription shows under the button, otherwise "Couldn't send your feedback. Try again." A CancellationError goes back to rest quietly.
  • topics is a list of FeedbackForm.Topic, each an id, title, SF Symbol and the message prompt it brings. Topic.defaults is .bug, .idea, .billing and .other.
  • accountEmail is where replies go for a signed-in person, and the thank-you names it. Leave it out and the block asks for an optional email, checked for its shape when given.
  • deviceDetails is what Include device info sends, as DeviceDetail label and value pairs. Leave it out for FeedbackForm.currentDeviceDetails(): the app's version and build from the bundle, the system name and version, the model identifier and the language. The toggle starts on and the list shows under it, so nothing is sent unseen.
  • messageLimit defaults to 1000 characters; maxScreenshots to 3, and 0 hides screenshots.
  • onDone is called by Done on the thank-you; close your sheet there. The form resets either way.
  • Haptics: a selection tick for the rating and topic, a warning when Send finds something missing, success when it lands, an error when it fails or a picked image can't be read.
  • VoiceOver reads each segment as "4 of 5, Good" with the selected trait, chips by their titles with the selected trait, the message count as "69 of 1000 characters", each thumbnail with its Remove screenshot button, and each device line as one element. It announces refused sends, removed screenshots and "Feedback sent. Thank you." Screenshot tiles shrink at accessibility sizes and every control is at least 44 points tall.
  • Reduce Motion turns every change into a short fade.
  • FeedbackFormExample at the end of FeedbackForm.swift is the Send feedback screen from the preview, for a signed-in person, with fixed device details so every run reads the same. It reads the theme from the environment; pass wrapsInNavigationStack: false to push it in your own stack.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • Cards are color.surface with radius.lg and 16 point padding, 24 points apart; card titles are type.headline, "Optional" and the screenshot count type.footnote in textTertiary.
  • Rating segments are 48 points tall at radius.sm on fill with a separator ring; the chosen one is textPrimary with surface figures. Topic chips are capsules the same way, with type.subhead medium labels. Selection stays in ink so the accent belongs to Send.
  • The message is a well on fill at radius.md with a separator hairline that turns to textPrimary when focused and to danger on an error; input type.body, prompt textTertiary, count type.caption with monospaced digits.
  • Thumbnails and the Add tile are 64 by 96 points at radius.sm with a separator ring; the remove button is a 22 point surface circle with a textPrimary cross. The device list sits on fill in type.footnote.
  • The switch is accent with an accentOn thumb. Send feedback and Done are accent with accentOn in type.headline, radius.md, 52 points.
  • The thank-you title uses the display face (type.face) at 20 points, capped at semibold, with a checkmark.circle in textPrimary and the line under it in type.subhead textSecondary.
  • States move with motion.snappy, the thank-you with motion.smooth, presses with motion.standard.