quicklookjs provides a macOS Quick Look Previewing extension that displays a web page. By packaging this preview extension with your native app, and replacing the web page with your own, you can implement a Quick Look preview experience using HTML/JavaScript (or a web framework of your choice).
The first step to creating a Quick Look preview is to write the preview page! You can see an example preview page, included with quicklookjs, at preview.html.
JavaScript in a quicklookjs preview page can use two functions on the global quicklook
object, getPreviewedFile
and finishedLoading
, to implement previews:
<script>
// We're using an async function so we can more easily interact with Promises returned by quicklookjs.
// This isn't required; you can always use .then() instead of await.
async function main() {
// Step 1: get the file that we're supposed to show a preview for.
// `file` is a File object, the same as if the user had dragged & dropped the file into your page.
const { file, path } = await quicklook.getPreviewedFile();
// Step 2: ...do anything you'd like in order to create a preview of the file!
// File inherits from Blob (https://developer.mozilla.org/en-US/docs/Web/API/Blob), so you can
// use Blob APIs like `text()` or `arrayBuffer()` to read the file.
// Step 3: tell quicklookjs that we're ready to display the preview.
await quicklook.finishedLoading();
}
main();
</script>
Other than these two functions, the preview implementation is totally up to you. Get creative! π¨
To make your preview page available to macOS, it needs to be bundled inside the App Extension provided by quicklookjs.
-
Install this package.
npm install --save-dev quicklookjs
-
When packaging your app, copy the
.appex
bundle into your application at.../Contents/PlugIns
:mkdir -p MyApp.app/Contents/PlugIns cp -R node_modules/quicklookjs/dist/PreviewExtension.appex MyApp.app/Contents/PlugIns/PreviewExtension.appex
If you're using electron-builder to package your app, you can do this by adding an
extraFiles
entry to your builder configuration:"extraFiles": [ { "from": "node_modules/quicklookjs/dist/PreviewExtension.appex", "to": "PlugIns/PreviewExtension.appex" } ],
You might also want to perform the following steps as part of an
afterPack
script. -
Edit the extension's Info.plist to suit your app:
-
The extension's CFBundleIdentifier should be prefixed with the containing app's CFBundleIdentifier. For example, if the app bundle ID is
com.example.MyApp
, the extension's bundle ID could becom.example.MyApp.PreviewExtension
. -
Update the
NSExtension.NSExtensionAttributes.QLSupportedContentTypes
with an array of the file content types you support. These can match the system-declared UTIs, or if your app declares custom types, these should match theUTTypeIdentifier
entries in your app's Info.plist. (See Declaring New Uniform Type Identifiers for more info about custom file types.) -
Optionally customize the configuration dictionary under the
QLJS
key (more about this below).
-
-
Copy your preview page into the extension bundle. By default the extension will load the page at
PreviewExtension.appex/Contents/Resources/preview.html
which is pre-configured for you with an example page. The file name loaded by the extension is configurable. -
Re-codesign the extension. This step is important because the modifications you made to the bundle render the existing signature invalid, and macOS requires Quick Look extensions to be signed/sandboxed. An entitlements plist file is included with the quicklookjs package to get you started.
codesign \ --sign - \ --force \ --entitlements node_modules/quicklookjs/dist/PreviewExtension.entitlements \ MyApp.app/Contents/PlugIns/PreviewExtension.appex
Now your app has Quick Look support! π
You can customize some of the preview extension's behaviors by editing the QLJS
dictionary in its Info.plist. The currently supported keys are:
-
loadingStrategy
(required): one of two pre-defined string values:waitForSignal
: show the preview page only once it signals that it's ready viaquicklook.finishedLoading()
. This is the preferred loading strategy.navigationComplete
: show the preview page as soon as it loads in the web view.
-
pagePath
(required): the path to the HTML page that will be displayed as the preview, relative toPreviewExtension.appex/Contents/Resources
. In the example Info.plist this ispreview.html
. -
preferredContentSize
(optional): a string specifying the size of the preview window. In the example Info.plist this is{500,300}
. -
transparentBackground
(optional): a boolean specifying whether the web view should have a transparent background. This relies on undocumented APIs, so use it with caution.
Under the hood, quicklookjs loads your preview page in a WKWebView, and the quicklook
functions are provided in a user script.
In order to give your JavaScript code access to the previewed file as a File object, when you call getPreviewedFile()
, quicklookjs temporarily adds an <input type="file">
to the page, and sends a fake click event to the web view. This allows the native code to respond with a file URL, which the web view translates into a File object.