Skip to content
This repository was archived by the owner on Sep 6, 2019. It is now read-only.

spec(Loader): add initial spec#5

Merged
layershifter merged 4 commits intomasterfrom
spec/loader
Jan 11, 2019
Merged

spec(Loader): add initial spec#5
layershifter merged 4 commits intomasterfrom
spec/loader

Conversation

@layershifter
Copy link
Contributor

No description provided.

@dzearing
Copy link
Contributor

dzearing commented Jan 8, 2019

Minor feedback on naming:

Have you considered other names for this such as a Spinner, and if so what was the rationale with Loader? There is definitely a differentiation between an indeterminate spinner and a ProgressBar or ProgressIndicator. Maybe these are all variants of the same thing though.

A Loader implies something that actually does work rather than being a presentational component; require.js is a loader, so I was confused when i saw this come up.

@layershifter
Copy link
Contributor Author

Have you considered other names for this such as a Spinner, and if so what was the rationale with Loader?

You can check Loader.mdx file in this PR (and made there a small investigation):

  • pull this branch
  • run yarn && yarn start

A Spinner is definitely widely used as the name. But, we discussed this previously with @levithomason:

Note we call this a "Loader" as it is not required to "spin" in all themes. Some theme may have a different animation.
microsoft/fluent-ui-react#666 (comment)

I have the same opinion there, Spinner is too specific for me. For example, not all loaders there do actually the "spin" action.

@dzearing
Copy link
Contributor

dzearing commented Jan 8, 2019

That's fair reasoning, sorry I should have looked at the PR content! :)

What about Progress?

<Progress variant='bar' value={.5} /> or
<Progress variant='circular' />

Truthfully a progress bar and a spinner probably could be combined. Both can be either determinate or indeterminate. They just look different. Similar to a primary button vs a primary circular button.

@layershifter
Copy link
Contributor Author

layershifter commented Jan 9, 2019

That's fair reasoning, sorry I should have looked at the PR content! :)

NP 😺

What about Progress?

We want to define it as a separate component, instead of a Loader it can have state (i.e. progress, value). For reference, almost all libraries define Progress as a separate idea:

I've seen an indeterminate Progress in Fabric UI, MUI, Onsen UI and Vuetify. Do you have more examples? But, they don't separate components between Loader and Progress as I have seen.

Personally for me, it looks a little strange because I think that Progress as the component should have a determinate value. However, if we will take a look into the dictionary, the progress in almost cases will be not clearly defined 🤔

@levithomason
Copy link
Member

levithomason commented Jan 9, 2019

Progress

There is a standard HTML element which establishes the name <progress> as a progress bar. If HTML conventions exist, we'll always adhere to those first.

<progress value="22" max="100"></progress>

image

Spinner / Loader

Spinner is widely used and it makes this decision a little more difficult. The term Loader is not rare by any means:

https://www.w3schools.com/howto/howto_css_loader.asp
https://loading.io/css
https://react.semantic-ui.com/elements/loader
https://www.npmjs.com/package/react-loader
https://www.npmjs.com/package/react-loading

In fact, the terms are often used together "loading spinner". This is true in component names and even icon names, such as <Icon name='loading spinner' /> in Semantic UI where the icon shape is called a spinner and the loading term adds a rotating animation to any icon.

Naming Principles

We fall back to naming principles to decide these things:

  1. Natural Language - Use terms found in natural language, opposed to jargon.
  2. Imprecise - Use imprecise terms which give leave room for variations to co-exist with the same name.
  3. Void of implementation - Do not include implementation details in the name, causing the name to become invalid once the implementation changes.
  4. Usefulness - If a name proves to more useful across more applications, without sacrificing any other principles, it may be considered even if it is not the most common.

This is the reason we use "primary button" vs "blue button" and "loader" vs "spinner".

Examples of non-spinning loading indicators:
http://g.recordit.co/nzO57yIwcS.gif
http://g.recordit.co/ZOSOy8uRiu.gif

It would be unfortunate if the majority of loading indicators in 2023 didn't spin anymore, but maybe pulsed, and our component was called "Spinner". We'd eventually want to rename it "Pulser" if we followed that logic. It's intent and usage, however, will never change. It will always be used to indicate that something is loading. So names should follow intent and usage, when possible.

@layershifter
Copy link
Contributor Author

Going to merge this PR, feel free to propose any changes via new PRs 👍

@layershifter layershifter merged commit d97ef5b into master Jan 11, 2019
@layershifter layershifter deleted the spec/loader branch January 11, 2019 09:06
@dzearing
Copy link
Contributor

dzearing commented Jan 11, 2019

Just some more info:

A ProgressBar or ProgressIndicator can be indeterminate or determinate.

A Spinner, while today it typically indeterminate, could also be determinate. See this issue:

microsoft/fluentui#7244

image

So the only difference we're seeing between these two is style variant. So I'd love to agree on some single name here with some variant.

Also fwiw on the progress html element mention above, there is also button, yet we have Button components with variations like circular. So, similarly, modeling some form of progress to follow this semantic idea, with variants, would make a lot of sense.

I think we'd still prefer Progress over Loader, as Loader still, to me, draws association with async loadable utility kind of thing (react-loadable?)

@dzearing
Copy link
Contributor

Including @Jahnp @aditima @micahgodbolt

@aditima
Copy link
Collaborator

aditima commented Jan 11, 2019

Naming is hard :) @levithomason, the naming principles you listed above make a lot of sense.

To me, the name Loader is very specific about the context in which it is used. We will want to use this component in various long running operations that are not necessarily loading, like deleting, move/copy etc.

Also, whether we do a determinate or indeterminate indicator often depends on the back-end capabilities and not a real semantic difference. I feel more comfortable with these being just variations of the same component, as opposed to completely different components.

Not sure if Progress implies linear, but at least English term seems pretty generic.

@dzearing
Copy link
Contributor

Minor note as well, MUI uses <LinearProgress/> and <CircularProgress/>. I do agree with @levithomason that keeping the visuals out of the component name makes a lot of sense. I think these are just variants. But then...trying to fit into the rules above; are these variants "linear" and "circular", or "condensed"?

@levithomason
Copy link
Member

levithomason commented Jan 12, 2019

Valid points @aditima and @dzearing, I really appreciate the input. Component boundaries are both difficult and very interesting.

After the below deep think and review, my take aways are:

  1. This is a single concept from a design perspective
  2. There are multiple components from an engineering perspective
  3. Our specifications need an updated format to handle both

We probably need to start including 1) definitions 2) states and 3) variations with our specs. This should help us find the balance between design guidelines and engineered component boundaries.

I might suggest the following components based on the below findings:

  1. Progress (automatic quantized progression)
  2. Steps (manual progression)
  3. ActivityIndicator (infinite activity)
  4. Placeholder (skeleton screens)

These are perhaps all part of the "Loading" category.


The Long Story


Single API

I can see the "something is progressing" similarity between a Loader and a Progress component. If we consider what the API might look like for using a single component:

<ProgressIndicator bar />            // horizontal progress bar
<ProgressIndicator bar circular />   // circular progress bar
<ProgressIndicator spinner />        // an infinite loading animation
// etc

These cases make sense, though, I see a lot of conflicts once you get into defining the specifics of each of these. Example, you would need properties for defining a progress bar that would not apply to the spinner case, etc.

It seems design guides tend to think about pending activity as a single category, such as the Material UI guide on "Progress & Activity" and Apple's guide on "Loading", whereas, engineering implementations tend to separate the concerns. This makes sense due to the constraints of designers vs engineers, but also makes naming quite difficult.

This may be showing us we need to get into naming of the actual states, anatomies, and properties. It just might be that the spec gives the names alone, but the implementation might structure those differently, as seen with the Material IO guide on "Progress Indicators" vs the Material UI components CircularProgress, LinearProgress etc.

Differences

I think there are enough differences in the properties, anatomy, and usage of these two components that also warrant a component boundary.

Progress Loader
Shows the progression of a task Tells the user to wait
Starts at 0, has a discrete step value, and a completion Does not start or end, is infinite
Displays percentage or "x of total" Has no units
Often includes a readout of the current value Has no value
Anatomy has a track and bar Anatomy has an animated area
Moves on completion of steps Is a an infinitely looping animation
Best for longer running tasks Best for shorter running tasks
Usually appears alongside other content Usually used in place of content
Often appears attached to other components Cannot attach to other components
Sometimes x/y centered Almost always x/y centered
Rarely dims the background Often dims the background
Has unique states like error, disabled, complete, etc Has active and indeterminate states

Similarities

There are few things in common, such as both are used when something is pending. However, under this definition we might ask why Placeholders or Shimmers are also not the same component. <ProgressIndicator image />?

There is precedent for component API boundaries which have great similarities. Such as an Image and an Avatar. From an engineering stand point, the boundary is useful as it allows us to target styles, anatomies, and variations without abusing abstractions.

IMHO, merging the "loading" and "progress" concepts into one component would be difficult to maintain.

Loader Naming

I definitely agree that the term Loader has room for improvement. Let's look around a bit more at namings. It seems there are several purposes, indicate infinte loading, show automated progress, show step driven progress, and stubbing pending content.

Source Progress Bar Progress Steps Loading Spinner Content Placeholder
Apple Design Progress Bar -- Activity Indicator Placeholders
Atlaskit -- Progress Tracker, Progress Indicator -- --
Bootstrap Progress -- Spinner --
Carbon -- Progress Indicator Loading, InlineLoading --
Fabric UI Progress Indicator -- Spinner Shimmers
Foundation Progress Bar -- -- --
Material Design Progress Indicator Steppers Progress Indicator Placeholder UI
Material UI Progress Steppers Progress --
Primer Progress -- -- --
Semantic UI Progress Steps Loader Placeholder

Doing some Google searches and reading around design articles, I also see Skeleton Screen as an emerging term for content placeholders.

@dzearing
Copy link
Contributor

Reading through the differences table above, I still think that both can be either determinate or indeterminate.

Both bar and spinner scenarios can be either determinate or indeterminate:

You may have a series of bars showing progress on a variety of operations. Some are determinate, while others may simply be indeterminate because the operation duration is unpredictable. For this case, yes you could use a mix of bars and spinners, but this would result in some ux asymmetry.

Youtube-like bar loaders at the top, below the header, are often indeterminate. Sometimes they "fake" determinate (e.g. they progress artificially and slow down exponentially as they get closer to 100%). Other times (e.g. "dancing ants" in Metro ui) they embrace being indeterminate. Still a horizontal bar like unit.

You may use determinate spinners due to ui spacing. E.g. a button which represents a progressing, determinate number of steps may want to use a determinate spinner inline. Again, due to ux aesthetics, you wouldn't represent this as an inline bar in the button.

The shared commonality here is that bars vs spinners is really boils down to a UX aesthetics decision I think, and both cases have determinate and indeterminate representations.

I do think "circular" vs "horizontal" are mutually exclusive.

// Indeterminate bar
<Progress /> 

// Determinate bar
<Progress value={.5} />

// Indeterminate spinner
<Progress circular />

// Determinate spinner
<Progress circular value={.5} />

// And even then, I'm a little unsure in the word "circular"... could be a square right? Options:
<Progress compact />
<Progress type="compact" />
<Progress variant="compact" />

Just to reiterate though... in the screenshot I posted above, you have spinners that have a unit (MB) and a value.

The only real distinction I can think of is that we've seen requests for small/medium/large spinner variants, but never for small/medium/large bars. That's what leads me to the "variant" concept. If we want to provide N visual representations of progress, using a variant prop would leave that open a bit.

@levithomason
Copy link
Member

Confirming indeterminate progress indicators are a thing regardless of their shape (bar or circular or something else).

We should probably start a new PR or issue that further specifies the properties of components related to progress and activity. I'm also thinking we need to support some kind of wiki footnotes where we can reference sources for our findings.

Loading Spinner vs Circular Progress

Just to reiterate though... in the screenshot I posted above, you have spinners that have a unit (MB) and a value.

Note, the screenshot posted is not a spinner but a circular progress bar. The two are fundamentally different. Progress bars have a track, a bar, a unit of measure, current value, total value, and they end on completion. Loading spinners have none of these properties nor anatomy.

Loading Spinner

  • infinite looping
  • no unit of measure, no current value, no total, no completion
  • track and bar shape only accounts for 1 of a plethora of shapes

Except for the track and bar design, this shows how none of the progress properties can be applied to most loading spinners. There is no way to indicate a progression from 0 to completion.

image

Circular Progress

  • not infinite, progress from empty to full once
  • has a unit of meansure (time, percent, steps, etc), current value, total value, and completion
  • always has a track and a bar

While you can put a circular progress bar into an indeterminate state and it looks like a loading spinner, this only accounts for one shape of a loading spinner. Designing a language for the below examples would be pretty straight forward when limited to cases of progression from 0 to complete. However, the language of this component does not contain the needs of the loading spinner shown above.

image


Since we need to support all loading spinners and all forms of progress bars it isn't feasible or reasonable to attempt and put all these needs behind one engineered solution. From a design guide perspective, they do belong in the same category.

@aditima
Copy link
Collaborator

aditima commented Jan 16, 2019

Thanks @levithomason. I think I am getting sold on the idea that 'determinate' and 'indeterminate' are two different entities from an engineering point of view, and the various shapes are just variants of each. Design needs to be responsible for keeping these visually consistent - it doesn't make sense for a circular determinate progress to look too different from a circular indeterminate progress in the same product.

What is the big difference between 1. Progress Bar/ 2. Progress Steps and 3. Loading Spinner/ 4. Content Placeholder in you chart above? Seems like 1 and 2 can be served by the same determinate component and 3 and 4 by the indeterminate one.

@levithomason
Copy link
Member

What is the big difference between 1. Progress Bar/ 2. Progress Steps and 3. Loading Spinner/ 4. Content Placeholder in you chart above? Seems like 1 and 2 can be served by the same determinate component and 3 and 4 by the indeterminate one.

In some of the themes these are very similar components. However, as with the extreme variation of loading spinners I don't think it will be feasible to put all "step" components into the same component as the progress bar. We'd need to do another deep dive on step components, but here's a quick peek to see:

image
image
image
image
image
image
image
image

As shown, Steps appear as a group of Step components. Each step can have a label/text, an icon, and a state (active, complete, disabled, pending, etc). The styling is also typically quite different than a Progress Bar, though again, sometimes it is similar.

I think anytime there is significant departure in anatomy and properties, there is likely an engineering component boundary. Example, most "Progress Steps" do not have a track and a bar (anatomy) and they do not support percentages. Steps are more about discrete labeled sequences. Progress Bars on the other hand typically support a bar only, so there are no discrete "steps" within it to give state and style to. Again, from a UX or design perspective I think these belong to same subdomain, however, from an engineering point of view managing the branching of logic, anatomy, and properties would be very difficult in a single component API.

@levithomason
Copy link
Member

For content placeholders, see the links in the comparison table above. Content placeholders are just gray boxes and circles shaped paragraphs and images. These are also very distinct from all the other forms of progress indicators.

@dzearing
Copy link
Contributor

One other alternative that was suggested for indeterminate progress was just Busy. It encompasses more scenarios than just loading (e.g. calculating a value, posting results, abstracting many long running operations.)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants