https://github.com/ckeditor/ckeditor5-image/issues/6 started general discussion about image feature UI/UX. In this ticket, I'd like to start a discussion about the details of inserting images.
There are 4 ways of inserting images:
Note: This, in fact, can be generalised to any media/files. We're talking here about images because that's the first kind of media which we'll support. In the future, this system can be extended to any embeddable file.
After a short discussion in the office, we have two proposals.
In this approach, there will be an "insert image" button (in the toolbar or wherever someone wants it), but it will have a minimal behaviour – i.e. it will open the native file browser. You can pick the file and it will be uploaded and inserted into the editor.
Inserting images via URL would be solved by handling pasting URLs into the editor.
And dropping images into the editor will also be handled.
There will be no support for custom systems (like CKFinder). Those systems will need to bring their own integrations – e.g. a new button.
In this approach, there will be an "insert image" button which will open a panel in which 3 options will be available: the user will be able to either chose a file from disk, drop it into the panel, paste URL (into an input). Also, other systems will be able to integrate themselves with this panel.
Besides that, the user will also be able to drop files into the editor content and paste URLs directly into the content, like in the minimal approach.
Waiting for your feedback đź“» !
There are 4 ways of inserting images:
You missed one of the most important use cases recently: pasting images that are in the clipboard.
There will be no support for custom systems (like CKFinder).
This is not possible. It is actually a requirement to integrate even the basic support with third-party systems. The one and only use case that doesn't require it is the "url" option.
All images that have no url need to be sent to a server solution that will accept them, save them and return an url to reach them. CKEditor will not provide this ofc, so there must be ways to integrate them (either configuration or plugins... or both).
Once integrations are in place, even images with url should be sent to the server (based on configuration) because most of the times one will not accept images being served from other (potentially unreliable) websites.
by dropping,
When it comes to dropping, much probably the righ way to do so is with integration with magic-line. That's how Medium works, in fact, and is a good UX.
Minimal
Image insert panel
I think we can rename these and come with three independent UX solutions instead:
We should aim for "1+2 (a and b)" but we can do it in a continues development approach, first "1", then "1+2.a", then "1+2.b". Many will still prefer "2.a", so we should make it in a way that one can decide to have that option instead of "2.b".
You missed one of the most important use cases recently: pasting images that are in the clipboard.
Right, +1.
This is not possible. It is actually a requirement to integrate even the basic support with third-party systems. The one and only use case that doesn't require it is the "url" option.
Just to make sure that we understand each other. What I meant is that in such a solution 3rd party systems would need to build their UI from low level blocks that we'd provide. E.g. we'd provide notifications, progress bar, intercepting files, perhaps a whole upload mechanism. Just without the UI.
We should aim for "1+2 (a and b)" but we can do it in a continues development approach, first "1", then "1+2.a", then "1+2.b". Many will still prefer "2.a", so we should make it in a way that one can decide to have that option instead of "2.b".
So what do we want to have in v1.0.0? Just "1+2.a"? Because if we're thinking about "2.b" as well, then we'd need to design this panel and I need to predict that in our sprints.
What I meant is that in such a solution 3rd party systems would need to build their UI from low level blocks that we'd provide.
3rd parties MAY implement a whole UI/UX for their services, but it will be generally pointless because there is a common expected UI/UX that fit most solutions and this should be provided by us. The role of third-parties is simply connecting the editor to the backend through configuration and API.
Btw, when I talk about 3rd parties, I' talking about "upload" only, not "file browsers" (like CKFinder), which is a different story.
So what do we want to have in v1.0.0?
As a minimum, we need "1".
I would them tentatively include "2.a" first, followed by "2.b". But if there will be no time for them, they can come right after v1.0.0.
To start off, I see the following sources (flows) of data we need to consider:

I hope I didn't forget something ;-)
For discoverability reasons, in the final implementation, we need to have a button, which gives the user a UI to insert the image.
It may look like this:

or this, because image URL is a secondary thing:

or even like this, to clearly separate things:

Whichever we decide is best, it resolves the following data flows:

When the file is uploading, the actions which make no sense in the UI will be disabled, still allowing the user to cancel the process:

Unlike in v4, I see a clear progress indicator per image. It feels smarter to me than a global stack of progress–bars, each one visually detached from the actual media it belongs to. It also means fewer problems with progress-bar positioning heuristics and so on.

The image will have a contextual toolbar synchronized with configuration, also allowing the user to enter the alternating text, which the key to the semantic content here.
When the image is focused, the image caption with placeholder text will be displayed allowing the user to enter the caption. If there's no caption displayed, the container and placeholder will disappear when the image is blurred. We already agreed on this, hoping it will not bring too much distraction.


OTOH, if we already need to implement the upload integration, progress indicator and so on, we could as well start with this one

in any of aforementioned variants (collapsed input, tabbed, whatever). That would give us 1., 2., 3., 4.a. and 4.b.
I have many. TBH, it's a very, very complex feature with multiple data flows, contradicting requirements to satisfy different user needs. So here we go:
I have doubts about having to UI for a single image feature. I mean the panel, which is attached to the toolbar to upload things and a contextual toolbar, attached to the image to manipulate it.
On one hand, if we decided to have it all in one place, we'd create a monster, just like in v4. Most people will D&D only and they would only get annoyed by the superfluous UI they don't use.
On the other hand, it may be unclear why some things are semantically here, and some there, if they are the part of a single feature. Why link fits in a single panel, always in the context of selection but the image is split? What should we do about it? It's a clash of contradicting UX requirements.
In what I proposed, there's no way to replace the image. I noticed that it's a common feature in the majority of editors. TBH, I've never replaced one in my life, usually deleting it and putting a new one, but still – I'm not a regular user of the application, so my opinion is probably biased.
The problem with my design is that there's no way to allow it easily. If by the button in the contextual toolbar, what should display then? That huge panel normally attached to the toolbar? What if the toolbar is off–screen? What if there's no toolbar? Etc.
How to allow integrations with 3rd party services like CKFinder? I decided to use a "Browse files" button:
To start off, I see the following sources (flows) of data
It looks great. The only exception is that URLs may also have to be sent/uploaded to the configured system, based on configuration.
If only because people might use URLs which don't have an explicit extension (like .jpg, or .png), which are images but our auto–hoisting system will not be able to recognize them.
Just a comment on this... our URL detection system should not be based on file extensions but on the content-type of the URL response. Something like this:
HEAD request is made with the URL. The content-type is retrieved.Insertion stage
At a first glance, it's a very nice proposal.
I immediately thought that the "Browse Files" button would be the one used to search for an image file in the computer. Much later on, I understood that this is the File Manager thing and figured out that I should have read the "cloud" box. In any case, the message in the box did make that clear for me as well. This made me think that the proposal is not working.
I think that the box should be used for DnD, exclusively. At that point, the iconography should be more related to that. Other options could go separate.
Uploading in the panel
I don't think that upload should happen in the panel. The outcome of using the panel should be exactly the same as dropping or pasting directly into the editor. This makes me think that the "Insert" button may be irrelevant, except for the URL field, so it could appear next to it only.
Uploading in editable
The fancy uploading thing (super cool, btw) should happen only if the image is not in any way available in the editor before uploading. I mean, the real image should be shown to the user. They should not even notice the difference once the upload is complete. It should look instantaneous to them.
I have doubts about having to UI for a single image feature.
Sounds very intuitive for me.
In what I proposed, there's no way to replace the image.
I don't think we must care about this at this stage. One will be able to replace it by deleting the old one anyway.
How to allow integrations with 3rd party services like CKFinder?
I agree that an action, like a button the way to go.
It just came to my mind that many implementations will not have a fixed toolbar. This gave me one interesting idea: what if the panel is inserted in the content, where the final image will end up?
The panel would stay selected much like a widget. ESC or Cmd+Z would undo the panel itself.
Considering that we have many options in the panel, one way to propose it could be:
| Drop Here |
+-----------------------+
or
- [Select a file] from your computer
- [Browse] the image manager
- *Paste the URL* of an image right now
Just a comment on this... our URL detection system should not be based on file extensions but on the content-type of the URL response. Something like this:
URL pasting is detected.
A HEAD request is made with the URL. The content-type is retrieved.
Plugins can decide to change the URL to something else, based on the content-type.
I think that the box should be used for DnD, exclusively [...]
I don't think that upload should happen in the panel
These statements contradict each other. What do you mean?
The fancy uploading thing (super cool, btw) should happen only if the image is not in any way available in the editor before uploading. I mean, the real image should be shown to the user. They should not even notice the difference once the upload is complete. It should look instantaneous to them.
Well, yes. But the progress must be clearly indicated. They must know that it's still uploading and they cannot simply save the node in CMS because they'll lose the image.
Considering that we have many options in the panel, one way to propose it could be:
Where would you see the alignment/alternating text options in such configuration? Two panels – one of the top with align/alt and the second one at the bottom to upload/set URL?
I re-read your comment @fredck and I found out that what you wanted to communicate is that the image should be uploaded/inserted via widget, which is already in content, like this

or simply

Right?
Right?
Yes!
We could play a lot with shapes and styles too


But I'm worried that what we insert here is not what the user will expect. I mean, if the styles are configured so each image is 50% wide, then what we insert here (the "upload widget") will not correspond with expectations. The wide widget will convert into a narrow image when the upload starts. And if we decided to style the "upload widget" like the image, we may find out that for some styles (narrow editor, narrow responsive image), there's no space to display the UI with instruction and buttons.

This approach is nice but I'm afraid there's too much risk with unpredictable styles. WDYT?
- So for each link pasted into the editor, a request will be performed? What if someone edits a document containing a list of 300 links to some resources? 300 requests to check if any contains an image?
Not applicable... see 3.
- How long would it take?
It is supposed to be super-fast, but it depends on the url.
- Or maybe such a request should be performed only when a single link is being pasted?
Yes!
- Is it possible in terms of security (cross-site requests like that)?
Yes and no :( CORS can block it... anyway, we may think about it... we can also use both ways, extension (translating it to Content-Type) and a HEAD request.
As for the HEAD request, we can even think about a proxy for it... a known server that is used as a HEAD request pass-thorugh (basically making the request from the server). Ofc, this would not be available out of the box, but it could be a nice addition for websites that want to have it.
I'm still liking the idea of the in-place panel... your proposal is very nice.
Well, yes. But the progress must be clearly indicated. They must know that it's still uploading and they cannot simply save the node in CMS because they'll lose the image
This can be an issue no matter what, but i think that, to make it right, it should be a CMS feature. I mean, the CMS should wait for the images to be uploaded or notify the user to wait for it. We should just expose a way to validate it.
Wow, @oleq, impressive work! The excellence and thoughtfulness is obvious.
Thank you, @fredck for developing CKE5 in the open!
@fredck What about:
Full–width widget which is converted into an actual image as soon as the preview of the image is available.

vs.
An unpredictable image widget from the very beginning containing upload tools?

That's interesting, but I think that the second option goes against the idea of keeping the user focused on performing the task they're focused on.
When I click the image button, let me add the image first of all, because that's what I was expecting to do. I'm not interested in writing its caption or setting up its alignment... that was not my intention. I would even not feel safe to do anything else before being sure that my image is really there.
I UI that guides the user to perform what they're doing in that moment is much more efficient.
When it comes to "default style", we want to make it configurable, so there is the theoretical situation when there will be no configuration for "full size" image. Maybe we'll have just images on the right. Or maybe just left/right. Therefore the possibility of having this panel using the default style is definitely welcome.
I would not be so focused in this on v1 though, but I would take this in consideration during implementation.
When it comes to the icon inside the panel, well done for both of them ;) I may prefer the second one.
That's interesting, but I think that the second option goes against the idea of keeping the user focused on performing the task they're focused on.
Well, yes and no. If I click the "Insert image" button in the toolbar, I expect to get an image, not an intermediate UI that will, eventually, become an image.
So if my editor allows images with a caption, I expect to get an image with a caption, where I can choose the image (d&d, paste, upload, browse) and fill the caption.
Otherwise, if we decide to hide the caption before the user selects the image, we must reveal it as soon as the preview is available (i.e. image has been dropped, but still uploading). For me, it feels like a surprise.
OTOH, I got your point. If we go my way ("what has been inserted is an image, but there's no bitmap"), we must instantly show the alignment toolbar to keep the pattern, which could be too much distraction:

TBH, I don't mind. But I'm curious of other people's opinion about this topic.
Anyway, I found another issue that should be discussed:
Once the alt text is filled, it may look strange to the people because the placeholder describing the input is gone. Some people will open the existing document to edit and they'll see images like this with filled alt text and wonder what it is.

Do you also think this is a problem?
Do you also think this is a problem?
I never liked such fields without label right because of this. Got confused a few times in such situations.
In the other hand, if we show the tooltip balloon to the field, just like we'll do for the buttons, this may be (not perfect but) ok.
Btw, due to the limited space for the alternative text field, it will many times hard to work in it for a bit longer texts. It will be also constantly cut and hard to read.
What if the alternative text becomes a button that, when clicked, replaces the balloon with a new balloon where a bigger field (2 or 3 lines or auto resizable) is available. That button would then stay active if there is text in it.
What if the alternative text becomes a button that, when clicked, replaces the balloon with a new balloon where a bigger field (2 or 3 lines or auto resizable) is available. That button would then stay active if there is text in it.
+1
The other option could be to edit the alt text "on the image". That would implement the vision which @pjasiun had to "turn the image" and edit it on its back.
I'm also wondering whether the "upload" widget could not be exactly that – the image in an edit mode.
What if the alternative text becomes a button that, when clicked, replaces the balloon with a new balloon where a bigger field
If we hide the first balloon, then we need to design and implement a navigation between the balloons so the user can go back to the first balloon (that one with positioning controls). Way too much complexity for me.
If we display another balloon attached to the first one, like this

then we're creating a tree–like structure, which doesn't look good either. Besides, how to close the alternating text balloon? Clicking the button it is attached to will indicate that you disable the alternating text. If we put a small "x" in the upper-right corner of the alternating text balloon, it may work but it's still not clear enough what is the semantics of the button – does it disable alternating text? Or just open the UI needed to fill it?
I'll try to figure out some smart navigation between the balloons. Maybe it's a more promising concept after all.
Is it possible in terms of security (cross-site requests like that)?
Yes it is, but it'd be ugly. CORS may allow that, but you have no control over that (it's the server you request setting). And I don't like the idea of creating a general, untrusted and open proxy. Sounds crazy (just like oembed server in the past) and as a content author I wouldn't like my content's links to be sent through an untrusted server. Also, I'm not sure whether CSP isn't somehow affecting that too.
However, such a feature would be pretty interesting in some controllable scenarios (e.g. when developing Slack like app), so we may consider making this possible. But please, let's not waste our energy on that now.
If we display another balloon attached to the first one, like this
I don't like this option. A stack of balloons looks bad. What I think Fred might have in mind is replacing one balloon with another (or rather – one balloon's content with the other). Then you'd have space for "cancel" and "save" buttons and a label. It'd be like the link's balloon.
The navigation should be fairly simple as well – cancel/ok gets your focus back to the image or its toolbar.
Maybe

or

is enough.
Maybe
Why not similar to this:

But without "unlink"?
Did you see my second design in https://github.com/ckeditor/ckeditor5-image/issues/16#issuecomment-267346810?
Did you see my second design in ckeditor/ckeditor5-image#16 (comment)?
Yes, and, as a pedant, I wanted to say that this wasn't the spacing and buttons I'd like to see there :D. I know – it's the same, but for consistency with link balloon I'd like there to be 2 buttons (cancel is useful) and similar sizing.
As for the insert widget – I think this is a really interesting idea. Especially that thanks to the OT we can selectively undo insertion of the image, even if some collaborating user changed the content around and the user who wanted to insert the image clicked "cancel".
I was also thinking about keyboard navigation and focus managment and, while more tricky than in a panel, it should also be doable. After clicking the button, focus will be moved to the widget. Then, we need a feature in widgets allowing you to cycle focus through the widget's inputs plus a keystroke to get out of it and "in" again.
@Reinmar Thanks. I'm gonna just leave it here to satisfy your sense of aesthetics ;-)

Btw, I would change "Save" to "Ok".
Btw, I would change "Save" to "Ok".
Perhaps you're right. But this, along with icons, sizes, etc. are details we're gonna shape during the implementation phase. The overall concept is what matters at this stage.
Sorry if it was already mentioned, but how you want to show an upload error? I mean image should disappear when the error occurs, so it can not be shown in-place.
how you want to show an upload error?
Maybe the upload plugin must simply fire an event and leave to the implementation to decide what to do with it. Maybe this can be a generic error event so other plugins can use it as well and the implementation doesn't have to be specific to the image upload only.
For sure some generic events for uploads will be needed anyway because, for instance, the Save button on the page may need to be disabled as long as the upload is in progress.
My idea is that the upload progress and any kind status is very contextual i.e. directly in the widget like:

So this is also the right place to tell the user the image didn't upload/insert for whatever reason. I haven't designed it yet.
For sure some generic events for uploads will be needed anyway because, for instance, the Save button on the page may need to be disabled as long as the upload is in progress.
From UX point of view, it's an evil practice.
What if uploading 10MB image over a really poor connection? The user mustn't be aware of that; the connection might have just become sluggish. They have Internet access + they have an image they've just taken, nothing else actually matters for them. And just because of that we cannot trap them in the (any!) editor and force them to cancel each upload individually so they can eventually save their content (unblock "Save" button).
What if they wanted to go for the meeting or they just found you their plane is taking off in a few minutes? What if their laptop battery was dying? Should they lose their entire content because of that? Because they were unable to cancel all 10 slow image uploads on time and re–activate "Save" button? It's not right.
The upload is a background activity. If the content is saved before it finishes, it's simply discarded. But the rest of the content is saved nevertheless, immediately. It cannot block any top–level interaction with the editor.
I think it should be up to the developer what he wants to do with the information that the upload is going on. I went many times to the meeting with an open tab, but even if blocking close is a bad idea, he may want to show a confirmation alert that the upload will be canceled if he will close this tab (of application). We should allow him to do this.
About the upload error: note that the widget may not be visible when an error occurs. Do you want to keep the widget as long the user will not close it manually after the error?
I would not go so intrusive in the UI. As I said elsewhere, the user intention is inserting an image, not uploading a file, which is just a technical requirement. If everything goes smooth, the upload should pass almost unnoticed. User attention is required only in case of errors, because that will interfere with the user intention.
When it comes to errors, I proposed firing events only because we don't know what's the right way for errors to be shown to the user. This may, or may not, be application specific. This may be different depending on the creator as well. Therefore I propose:
When it comes to errors, I proposed firing events only because we don't know what's the right way for errors to be shown to the user.
👍
I'm also for keeping the stuff under the hood as generic as possible. But I think it's up to the feature to decide what to do with an error rather than to the creator.
For instance, if creator piped all errors to some notification system in a feature–rich environment, the user might end up trapped under the avalanche of error notifications, most of them irrelevant from their point of view while important notifications (image upload failed) go unnoticed.
Besides, it would also mean that the notification system must clearly distinguish information from various features so the user can visually tell one from the other, to actually make these notifications useful to the user. It's a tricky UX aspect.
Maybe
Developers can catch these events earlier and override the default behavior with anything custom.
might be the right solution to solve this. An event "pipe" which always ends up in "stderr" (some generic notification system) + some handlers to intercept those errors (like image displaying errors in own widgets).
What would such generic notification system look like now that each editor (creator) is a separate thing, no longer bound by CKEDITOR.instances?
If those errors were to be displayed e.g. on top of the viewport, how to aggregate errors from multiple editors?
And if the previous is somehow possible, how to tell one editor from another in such error stack so they make sense to the user (UX)?
Which part of code should initialize such "shared" generic notification system?
I like it. The only problem is that as long it is not a dedicated creator, but the generic one (like Classic on Inline) we do not know if it will be used with the upload feature or not. We can say that this error handling event is generic and should be implemented in every creator, because various plugins may fire it, but the true is (talking from the CKE4 experience) that mostly upload needed notifications.
Still, I agree we should have events and handle it in the implementation/creator, even if standard implementations will use some very basic error handling.
Also, maybe we should show the system alert if no one handles error message? I mean: implementation should handle it, but if not it would be better to have a system error then have no message at all.
What would such generic notification system look like now that each editor (creator) is a separate thing, no longer bound by CKEDITOR.instances?
This is not a big deal, IMHO. The one who creates the editor can attach listeners to it. That's it. You do not need any global object. If it's more convenient, developer can prepare a factory which will create an editor with attached listeners.
This is not a big deal, IMHO. The one who creates the editor can attach listeners to it. That's it. You do not need any global object.
but
Which part of code should initialize such "shared" generic notification system?
?
Not sure my proposal was clear. Such notification system is beyond CKEditor's scope and is application specific. We don't have to make assumptions not propose anything about it.
We can, instead, propose a default implementation in the creators, which is "per editor", not generic. For example, something similar to what we have in CKEditor 4.
Is this still a thing? The first thing we have had with the new editor is people uploading and saving before it is complete because the UX isn't very noticeable about the upload progress.
I'm going to disable the form submit while uploading and also (if I can with CSS) make the image fade until uploaded. But the suggestions in here for progress seem far better than what we have now.
We're revisiting this issue! 🎉
The main goal is allowing users to insert images via URL but also we may bring other improvements to the UX.
At this stage, we're going to drop the "placeholder" UX (first insert the placeholder, then upload/specify the URL) because:
So, at this moment there are 2 kinds of UI/UX we consider:



Drag and drop works as expected in the editor content, so there's no need to have this inside a popup.
Also, I think that dragging an image to a popup is not a good idea (you have to handle the visibility of the popup, but also you're loosing the context of the place where you want to upload an image). I would replace that area with a simple browse images or click to upload button.
Question
Do we consider enabling the image plugin for introducing the replace image option? ATM when image is selected, the toolbar option is disabled.
Do we consider enabling the image plugin for introducing the replace image option? ATM when image is selected, the toolbar option is disabled.
Yes, I think we should consider this option. IMO it's a valid use–case especially when the existing image:
Replace image saves a lot of :point_up:Â work.
Let's conclude this topic in #7439
Most helpful comment
To start off, I see the following sources (flows) of data we need to consider:
I hope I didn't forget something ;-)
Insertion stage
For discoverability reasons, in the final implementation, we need to have a button, which gives the user a UI to insert the image.
It may look like this:
or this, because image URL is a secondary thing:
or even like this, to clearly separate things:
Whichever we decide is best, it resolves the following data flows:
Uploading in the panel
When the file is uploading, the actions which make no sense in the UI will be disabled, still allowing the user to cancel the process:
Uploading in editable
Unlike in v4, I see a clear progress indicator per image. It feels smarter to me than a global stack of progress–bars, each one visually detached from the actual media it belongs to. It also means fewer problems with progress-bar positioning heuristics and so on.
After insertion
The image will have a contextual toolbar synchronized with configuration, also allowing the user to enter the alternating text, which the key to the semantic content here.
When the image is focused, the image caption with placeholder text will be displayed allowing the user to enter the caption. If there's no caption displayed, the container and placeholder will disappear when the image is blurred. We already agreed on this, hoping it will not bring too much distraction.
First implementation
OTOH, if we already need to implement the upload integration, progress indicator and so on, we could as well start with this one
in any of aforementioned variants (collapsed input, tabbed, whatever). That would give us 1., 2., 3., 4.a. and 4.b.
Doubts, issues and problems
I have many. TBH, it's a very, very complex feature with multiple data flows, contradicting requirements to satisfy different user needs. So here we go:
I have doubts about having to UI for a single image feature. I mean the panel, which is attached to the toolbar to upload things and a contextual toolbar, attached to the image to manipulate it.
On one hand, if we decided to have it all in one place, we'd create a monster, just like in v4. Most people will D&D only and they would only get annoyed by the superfluous UI they don't use.
On the other hand, it may be unclear why some things are semantically here, and some there, if they are the part of a single feature. Why link fits in a single panel, always in the context of selection but the image is split? What should we do about it? It's a clash of contradicting UX requirements.
In what I proposed, there's no way to replace the image. I noticed that it's a common feature in the majority of editors. TBH, I've never replaced one in my life, usually deleting it and putting a new one, but still – I'm not a regular user of the application, so my opinion is probably biased.
The problem with my design is that there's no way to allow it easily. If by the button in the contextual toolbar, what should display then? That huge panel normally attached to the toolbar? What if the toolbar is off–screen? What if there's no toolbar? Etc.
How to allow integrations with 3rd party services like CKFinder? I decided to use a "Browse files" button: