- Marijn Kruisselbrink
- Introduction
- Goals and Use Cases
- Non-goals
- Proposed API
- Detailed design discussion
- Stakeholder Feedback / Opposition
- References & acknowledgements
When initially shipping the File System Access API we shipped a bare minimum API surface for showing file and directory pickers. We're now proposing adding a couple of frequently requested (and commonly supported in other file picker APIs) options to let websites provide a couple more opportunities to influence the behavior of the file and directory pickers.
In particular this explainer addresses letting websites give suggestions for the name and location of files and directories that are being saved or loaded.
The overarching goal here is to provide websites the opportunity to provide the file or directory picker implementation suggestions for both the initial directory to show in the picker, and (in the case of save dialogs) the file name to save a file as. Specifically to help address the following use cases:
- User opens a file from their local file system, or from some cloud provider.
- User then picks the "Save As" option from the web application.
- User saves the file in a different directory, but using the name the file already had (without having to re-type the name).
- Users opens a file from their local file system.
- User then picks the "Save As" option from the web application.
- User saves the file using a different name, in the directory the original file exists (without having to re-navigate to that directory).
- User is editing a file from their local file system.
- User then picks the "Open" option from the web application to open another file.
- User can pick files from the same directory the currently open file is in without having to re-navigate to that directory.
- User picks "Insert image" in a web application
- A file picker pops up starting out in the users "Pictures" folder.
- User opens a document in a web application from directory A.
- User inserts an image into the document, by selecting a file from directory B.
- User opens a different document, from directory A without having to navigate to directory A again.
- Further image insertion operations should have their file pickers start out in the directory of the last image insertion as well.
All the above functionality is intended as hints/suggestions from websites to the file picker implementation to improve the end user experience. However implementations should not be required to always follow these suggestions. If for example a suggested file name provided by the website is deemed too dangerous to be allowed, implementations should be free to ignore the suggestion (or adjust the suggested file name to not be dangerous anymore).
const file_ref = await self.showSaveFilePicker({
suggestedName: 'README.md',
types: [{
description: 'Markdown',
accept: {
'text/markdown': ['.md'],
},
}],
});
We propose adding a startIn
option, that can be either a file or a directory
handle. If the passed in handle is a file handle, the picker will start out in
the parent directory of the file, while if the passed in handle is a directory
handle the picker will start out in the passed in directory itself.
Additionally, in a save file picker, if startIn
is a file, and no explicit
suggestedName
is also passed in, the name from the passed in file handle
will be treated as if it was passed as suggestedName
.
This lets you use startIn
for typical "Save as" UI flows:
async function saveFileAs(file_handle) {
return await self.showSaveFilePicker({
startIn: file_handle
});
}
And is also useful for cases where you a user is likely to want to open a file from the same directory as a currently open file or directory:
async function openFileFromDirectory(project_dir) {
return await self.showOpenFilePicker({
startIn: project_dir
});
}
// Used when prompting the user to open a new file, starting out in the
// directory containing a currently open file.
async function openFileFromDirectoryContainingFile(open_file) {
return await self.showOpenFilePicker({
startIn: open_file
});
}
// Used for example in a flow where a website wants to prompt the user to open
// the directory containing the currently opened file (for example for file
// formats that contain relative paths to other files in the same directory).
async function openDirectoryContainingFile(open_file) {
return await self.showDirectoryPicker({
startIn: open_file
});
}
To support saving files in or opening files from certain well-known directories,
we also propose allowing passing certain string values to startIn
to represent
these well-known directories. This would look something like:
const file_ref = await self.showOpenFilePicker({
startIn: 'pictures'
});
The possible values for startIn
would be:
desktop
: The user's Desktop directory, if such a thing exists.documents
: Directory in which documents created by the user would typically be stored.downloads
: Directory where downloaded files would typically be stored.music
: Directory where audio files would typically be stored.pictures
: Directory where photos and other still images would typically be stored.videos
: Directory where videos/movies would typically be stored.
Currently the Chrome implementation of the File System Access API remembers the
last used directory on a per-origin basis. To allow websites to remember
different directories for file pickers that are used for different purposes
(i.e. opening documents, exporting to other formats, inserting images) we
propose adding an id
option to the file and directory picker methods. If an
id
is specified the file picker implementation will remember a separate last
used directory for pickers with that same id
:
const file_ref1 = await self.showSaveFilePicker({
id: 'fruit'
});
const file_ref2 = await self.showSaveFilePicker({
id: 'flower'
});
// Picker should start out in the directory `file_ref1` was picked from.
const file_ref3 = await self.showOpenFilePicker({
id: 'fruit'
});
It is possible for suggestedName
to be inconsistent with the file types a
website declared as being the accepted file types for a file picker. There are
a couple of cases worth highlighting here:
-
If
suggestedName
ends in a suffix that is specified for one of the accepted file types, the file picker should default to that file type. -
Otherwise, if
excludeAcceptAllOption
is false (or no explicit accepted file types are provided), the "all files" options should be the default selected file type in the file picker. -
Finally, if neither of these are the case (i.e. the suggested file name does not match any of the file types accepted by the dialog), the implementation should behave as if
excludeAcceptAllOption
was set to false, and default to that option.
An alternative to 3. would be to reject if no accepted file types match the suggested file name.
Another alternative to 3. would be to append a suffix from the first accepted
file type to the suggested file name (or replace the extension from the
suggested file name with one that is accepted). This seems less desirable than 3
because this would mean that specifying an extension in the suggestedName
is
optional as long as excludeAcceptAllOption
is set to true, but then later
changing excludeAcceptAllOption
to false would suddenly change behavior and
possibly break existing API usage.
Both these attributes influence what directory the file picker should start with, as such it isn't immediately obvious what should happen if all are provided.
Our proposal is for it to not be an error to provide both startIn
and
id
. If a well-known directory is provide for startIn
, id
will take
precedence. That means that if a previously recorded path for the same id
exists, it will be used as starting directory, and only if no such path is
known will startIn
be used.
On the other hand if startIn
is a file or directory handle, it will take
precedence over id
. In this case startIn
specifies what directory the
file picker should start out in, and the ultimately picked directory will be
recorded as the last selected directory for the given id
, such that future
invocations with that id
but no startIn
will use the directory.
We could reject if both a startIn
option and id
are provided, to ensure only
one option controls which directory to start in. There don't see to be many
downsides to allowing both though, as recording the last used directory for
future invocations of a file picker without a startIn
option still seems
useful.
We could also have either id
or startIn
always take precedence over the
other. In some ways this might be less confusing, as it would always be clear
which one takes precedence, without having to know the type of what is passed to
startIn
. We've chosen not to do so though. Using a well-known directory only
as a fallback mechanism for the id
based directory matches what other similar
APIs do. Simultanously if a website explicitly specifies a concrete directory to
open the picker in by passing a file or directory handle to startIn
we also
want to respect that. Hence the precedence depending on the type of the startIn
option.
An earlier version of this document had separate startIn
and startInParentOf
options. This would enable websites to not only open file or directory pickers
in the same directory as a passed in directory handle, but also in the parent
directory of such a directory (without needing to have access to a handle for
the parent directory).
Having a single startIn
option results in a simpler and easier to explain and
understand API, whil still supporting all the major use cases. Websites will be
able to start file or directory pickers in any directory they have a handle to,
as well as any directory for which they have a handle to a file in said
directory. The only hypothetical use case that isn't covered by this is for
cases where the website wants the user to select a sibling directory to a
previously selected directory, but we're not aware of any concrete use cases
where that would be beneficial.
As mentioned in the non-goals section, all these attributes should be considered
suggestions or hints. This is particularly relevant for the suggestedName
option. The same concerns around writing to files ending in .lnk
or .local
as mentioned in https://wicg.github.io/file-system-access/#privacy-wide-access
also apply to letting the website suggest a user save files with these names.
User agents should do similar sanitization as to how the download
attribute
of <a>
tags is processed in https://html.spec.whatwg.org/multipage/links.html#as-a-download.
- Chrome : Positive, authoring this explainer
- Gecko : No signals
- WebKit : No signals
- Web developers : Positive, frequently requested (See #85, #144, #94 and #80.)
Many thanks for valuable feedback and advice from:
Austin Sullivan, Thomas Steiner