Skip to content

feat(expo-image): Add SF Symbol support for Apple platforms#41907

Merged
EvanBacon merged 28 commits intomainfrom
@evanbacon/expo-image/sf-symbol-support
Jan 20, 2026
Merged

feat(expo-image): Add SF Symbol support for Apple platforms#41907
EvanBacon merged 28 commits intomainfrom
@evanbacon/expo-image/sf-symbol-support

Conversation

@EvanBacon
Copy link
Copy Markdown
Contributor

Why

  • Not using SF Symbols on iOS is a smell that the app isn't written with UIKit/SwiftUI. We currently expose SF Symbols via the expo-symbols package, but this is clunky and out of the way for users. To make it much easier to stumble upon, I propose we add SF symbols support directly to our default image component (mirroring UIKit/SwiftUI image components).
  • The source prop extends our existing source system where we support URI strings such as https:// and local resources file:// along with cross-app resources ph://. Here we treat the SF symbols as a custom URI since they are local resources too sf:star — where the protocol is sf and the pathname is the icon name as-is. This is typed strictly while still allowing arbitrary strings by using the type sf:${SFSymbolNames}. This particular system should be capable of scaling to any other android equivalent (though we already just pass strings in as-is for resources).
  • SF Symbols are somewhere between an image and a font icon so the API can often be a bit clunky, e.g. (fontWeight, fontSize, color). I tried to add exhaustive support here so we can sense what it feels like. In the future, we could offer a more type-constrained compound component wrapper, e.g. <Image.SF /> but that opinion can be added later.
  • A hallmark feature of SF Symbols are the animations and transitions. I've added transitions to the transition prop and all the animations to the new sfEffect prop.
  • This implementation is currently missing multiple colors, and symbolType.
<Image source="sf:star" style={{ width: 16, aspectRatio: 1 }} tintColor="blue" />

In the future if we add fontSize and color style props then a Tailwind user could do the following:

<Image source="sf:star" className="text-base text-sf-blue" />

In my opinion, this API feels on par with SwiftUI in terms of ergonomics (minus the manual import for expo-image).

Test Plan

  • native-component-list page for Apple platforms.
Simulator.Screen.Recording.-.iPhone.17.Pro.Max.-.2026-01-02.at.15.14.25.mov

Checklist

Introduces SFSymbolLoader for loading SF Symbols via 'sf:' URI scheme in iOS. Updates ImageModule to register the new loader, adds detection logic in ImageSource, and extends resolveSources utility to handle SF Symbol strings.
Added 'expo-image' to dependencies and updated the static rendering index page to display an image using expo-image. Also updated .env and README.md with minor improvements for local development and Apple Team ID setup.
Introduces support for SF Symbol transition effects (iOS 17+) in expo-image, including new effect types such as 'sf:bounce', 'sf:pulse', 'sf:variable-color', 'sf:scale', 'sf:appear', 'sf:disappear', and 'sf:replace'. Updates the iOS implementation to handle symbol animation start/stop, tracks SF Symbol sources, and documents the new effects in Image.types.ts. Also updates the static rendering E2E test page to demonstrate symbol transitions.
Introduces direct SF Symbol rendering in ImageView.swift, bypassing SDWebImage to preserve symbol properties and support symbol-specific transitions and effects. Updates the static rendering E2E test to use 'sf:faceid' and comments out 'autoplay' and 'tintColor' for demonstration. Also adds logic for handling the 'sf:replace' effect and symbol weight parsing, and updates related type definitions.
Introduces a `repeat` property to the ImageTransition type and iOS implementation, allowing SF Symbol animation effects to repeat a specified number of times or indefinitely. Updates example usage and TypeScript types to document and support the new option.
Expanded the ImageTransition types and iOS implementation to support additional SF Symbol transition effects introduced in iOS 17 and iOS 18, such as bounce, pulse, scale, appear, disappear, wiggle, rotate, breathe, and draw-on, including their directional and layer-specific variants. Updated documentation and example usage to reflect the new effects.
Simplifies SF Symbol effect enums by removing scoped variants and introduces a separate 'scope' property for layer animation control. Updates iOS implementation to support new scope logic and adds support for 'sf:draw/on' and 'sf:draw/off' effects (iOS 26+). Adjusts TypeScript types and documentation to reflect these changes and updates example usage in static rendering test page.
Updated ImageProps to support SF Symbols via the `sf:` prefix and added the `sf-symbols-typescript` dependency. Adjusted example usage in the static rendering app to demonstrate new SF Symbol options and transition effects.
Introduces support for additional SF Symbol replace transitions: 'sf:replace/down-up', 'sf:replace/up-up', and 'sf:replace/off-up'. Updates iOS implementation to handle these effects and improves type definitions and documentation for transition options.
Introduces a new `sfEffect` prop for SF Symbol animations, supporting strings, objects, and arrays for more flexible configuration. Removes SF Symbol animation options from the `transition` prop and updates iOS implementation to handle multiple effects. Updates TypeScript types and documentation to reflect the new API.
Introduces a new ImageSFSymbolScreen showcasing SF Symbol effects (iOS 17+ and iOS 18+) using expo-image, including various animation and style options. Updates navigation to include the new screen for iOS, adds related environment variables, and a prebuild script for template usage.
Adjusts the Image component to default the contentFit prop to 'contain' instead of 'cover' for SF Symbol sources, preserving their aspect ratio. Updates resolveContentFit utility and passes an isSFSymbol flag to ensure correct behavior.
Introduces a new `symbolWeight` prop for SF Symbol images in expo-image on iOS, allowing font weight to be set directly rather than via URL query parameters. Updates the Image component and native iOS implementation to use this prop, and removes related query parameter handling. Also updates the changelog and example usages to reflect support for `source="sf:star"`.
Updated SF Symbol transition effect names from 'sf:replace/down-up', 'sf:replace/up-up', and 'sf:replace/off-up' to 'sf:down-up', 'sf:up-up', and 'sf:off-up' respectively across TypeScript types, iOS implementation, and example usage. This change improves naming consistency and clarity for SF Symbol transitions.
@EvanBacon EvanBacon requested review from Ubax and tsapeta January 2, 2026 23:17
Updated the resolveSfEffect function in Image.tsx to use multi-line parameter formatting for improved readability. No functional changes were made.
@expo-bot expo-bot added the bot: suggestions ExpoBot has some suggestions label Jan 2, 2026
EvanBacon and others added 2 commits January 2, 2026 15:20
Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
@expo-bot expo-bot added bot: passed checks ExpoBot has nothing to complain about and removed bot: suggestions ExpoBot has some suggestions labels Jan 2, 2026
@expo-bot
Copy link
Copy Markdown
Collaborator

expo-bot commented Jan 2, 2026

The Pull Request introduced fingerprint changes against the base commit: e889247

Fingerprint diff
[
  {
    "op": "changed",
    "beforeSource": {
      "type": "dir",
      "filePath": "../../packages/expo-image/ios",
      "reasons": [
        "expoAutolinkingIos"
      ],
      "hash": "a692ef6fbf6e8966ce701c78a6f31bfec4d7222f"
    },
    "afterSource": {
      "type": "dir",
      "filePath": "../../packages/expo-image/ios",
      "reasons": [
        "expoAutolinkingIos"
      ],
      "hash": "38e6c2ca1fd4462789170a7dc2dfe3079974973e"
    }
  }
]

Generated by PR labeler 🤖

Introduces the imageStyle prop to ImageBackgroundProps, allowing custom styles to be applied directly to the background image. This provides more flexibility for styling the image separately from the container.
@EvanBacon EvanBacon marked this pull request as ready for review January 7, 2026 18:22
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 7, 2026

Subscribed to pull request

File Patterns Mentions
docs/** @amandeepmittal
packages/expo-image/** @lukmccall, @aleqsio, @tsapeta

Generated by CodeMention

Co-authored-by: Aman Mittal <amandeepmittal@live.com>
Copy link
Copy Markdown
Contributor

@Ubax Ubax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exciting 🎉

Added minor nits

Deleted EXPO_NO_GIT_STATUS from the .env file as it is no longer needed. Refactored SFSymbolLoader.swift to use shorthand optional binding for the url parameter.
Updated Image.tsx to use more precise ImageStyle & TextStyle typings when flattening styles. Also improved handling of fontWeightStyle for SFSymbols by ensuring it is always a string when passed as symbolWeight.
@EvanBacon EvanBacon merged commit 22e8e44 into main Jan 20, 2026
11 of 14 checks passed
@EvanBacon EvanBacon deleted the @evanbacon/expo-image/sf-symbol-support branch January 20, 2026 05:35
EvanBacon added a commit that referenced this pull request Jan 21, 2026
# Why

- Follow up on #41907
- Add fontSize and color props to expo-image when using SF symbols to
match the style options of SwiftUI which would pair with Tailwind to
create a clean API: `<Image source="sf:star" className="text-lg
text-sf-yellow" />` -> Large SF star in adaptive Apple yellow color.

# Test Plan

- Added to NCL, built to ensure it runs.

---------

Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot: fingerprint changed bot: passed checks ExpoBot has nothing to complain about

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants