Pattern · Lists and Feeds

New

File List SwiftUI Block

A files section: storage by type, sort and list or grid, uploads with progress, rename, share, move and delete, and Add.

The files section of a folder, project or storage screen. A storage card splits the used space by type, the toolbar sorts by name, date, size or kind and switches between list and grid, and Add opens the system file importer or photo picker. Uploads show progress and Cancel and land as files, and every file has Rename in place, Share, Move and a confirmed Delete.

  • SwiftUI
  • iOS 17.0+
  • file-list
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.

  • Used of total with a bar and legend split by type
  • Sort by name, date, size or kind, in a list or a grid
  • Uploads with progress and Cancel that land as files
  • Rename in place, Share, Move and Delete with a confirmation
  • Add through the file importer or the photo picker

02

Implementation notes

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

A storage card at the top gives the used space as the block's one large figure ("18.4 GB of 50 GB"), the share used, a bar split by type in steps of the primary ink, and a legend with each type's size. Under it a toolbar sorts by Name, Date, Size or Kind, switches between a list and a grid, and Add opens a menu with Choose Files, which presents the system file importer, and Photo Library, which presents the photo picker; Add shows a spinner while your closure takes the picked files. Folders come first in every sort with their item count. In the list, each file shows its type symbol or thumbnail, its name, size and day, and an ellipsis menu; in the grid, a larger thumbnail with the name and size under it. Uploads in flight sit first with a thin progress bar, "Uploading 39.7 MB of 64 MB" and Cancel, and land as files when your model moves them into the folder. Every file has the same menu on a long press: Rename edits the name in place with its own working and failed states, Share opens the system share sheet through ShareLink, Move calls you, and Delete asks first in a confirmation dialog and dims the row while it works. An empty folder says so with an Add button, and passing nil shows grey shapes while the folder loads.

Notes

  • FileList(folder:uploads:initialSort:initialArrangement:onImport:onImportPhotos:onOpen:onRename:onMove:onDelete:onCancelUpload:) takes the folder, the uploads and a closure per action you support; leave one out to hide its control. It is a section: no navigation stack, background, padding or scroll view of its own.
  • FileList.Folder holds the items and an optional Storage. Folder.sample is the project folder from the preview.
  • FileList.Item has an id, name, Kind (.folder, .image, .video, .audio, .document, .pdf, .spreadsheet, .presentation, .archive, .other), size in bytes, modified, itemCount for folders, an optional thumbnail URL loaded with AsyncImage, and an optional shareURL for Share. summary gives the "2.4 MB · Oct 21" line.
  • FileList.Upload is an id, name, kind, bytes sent and total. Update it as bytes go up; when it finishes, remove it and add its Item to the folder, and the block moves it from one to the other.
  • FileList.Storage is used and total in bytes with up to four Segments (label, bytes), largest first. Used space not covered by the segments joins the last one. Leave storage nil to hide the card.
  • Sort is .name and .kind A to Z, .date newest first and .size largest first. Arrangement is .list or .grid; the block keeps both as its own state from the initial values.
  • onImport receives security-scoped URLs from fileImporter (any file type, several at once); call startAccessingSecurityScopedResource() while you copy them. onImportPhotos receives PhotosPickerItems (images and videos, up to 20). Throwing from either shows its errorDescription under the toolbar.
  • onRename(item, name) runs when the person submits the new name; the row shows a spinner, and a thrown error restores the old name with the message under it. Renaming from the grid switches to the list first.
  • onDelete runs after the person confirms. The row dims with a spinner until your model removes the item; a thrown error shows under it.
  • onOpen is called when a file or folder is tapped; onMove when Move is chosen, for your folder picker; onCancelUpload from an upload's Cancel.
  • Haptics mark a selection when the sort or the arrangement changes, success when a rename or delete finishes, and an error when anything fails.
  • VoiceOver reads the storage card as one sentence with each type's size, each file as its name with size and day, uploads with their percentage, and announces renames and deletions.
  • Reduce Motion turns every change into a short fade.
  • FileListExample at the end of FileList.swift is the Files screen in the preview: a website project on a 50 GB plan where a zip of site photos finishes uploading and lands as a file. 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, list rows at least 64 points with SPHairline dividers in separator inset to the name, and groups 24 points apart (space.xl).
  • The used figure is the block's one display moment: the brand's display face (type.face) at 28 points, type.numeralWeight capped at semibold, monospaced digits. Other text uses type.subhead, type.body, type.footnote and type.caption in textPrimary, textSecondary and textTertiary.
  • The storage bar and the legend dots are textPrimary at full, 55%, 30% and 16% on a fill track; upload bars are textPrimary on fill.
  • Type symbols sit on fill squares at radius.sm in the list and radius.md in the grid, in textSecondary.
  • Sort is a surface capsule with a separator stroke; the List and Grid switch is a fill track with the selection on surfaceElevated. Add is the one accent control, with accentOn text. Errors are danger.
  • Changes animate with motion.smooth and motion.snappy, and become short fades under Reduce Motion.