Library vs. Framework: What's the Difference?

Installing a package doesn't tell you how much of your application it expects to organise. One dependency might format a date and leave everything else alone. Another might determine how requests reach your code, where configuration belongs, and when your components are created or destroyed.
A library usually gives your application something to call or compose. A framework supplies a structure and lifecycle into which you fit your code. The distinction describes how you work with a dependency; it isn't a formally enforced label on a package registry.
Who Decides What Happens Next?
The familiar rule is that you call a library, whilst a framework calls your code. That's inversion of control: instead of writing the overall sequence yourself, you provide behaviour at points managed by something else.
Martin Fowler's explanation of inversion of control, published in 2005, describes that relationship as a key characteristic of frameworks. The framework coordinates activity, and application code supplies the pieces which customise it.
When a reporting task calls a formatting function, the application decides when the formatter runs and what to do afterwards. With a web framework, the framework receives the request, matches a route, invokes your handler, and processes the response. You supply the handler; it manages the surrounding request lifecycle.
That affects how you debug it. With a small function library, start with its arguments and return value. With a framework, you also need to know when it invokes your code, what context it supplies, and which conventions it expects you to follow.
A Callback Doesn't Automatically Make a Framework
A library can accept a callback and invoke it later without organising the whole application.
A sorting utility might call your comparison function. An event library might invoke a registered listener. Neither fact alone tells us how much structure the dependency imposes elsewhere, or whether its maintainers use "framework" to describe it.
I'd look at how much control it takes. Owning a single sorting operation is rather different from owning the rendering process or the request pipeline. Find out which decisions it makes for you and which ones you can change.
Why React Calls Itself a Library
React describes itself as a library for building user interfaces in its 2013 introduction. You can compose it with the other parts of an application, but it still controls rendering.
You describe components and let React coordinate their rendering. It doesn't prescribe the whole application architecture. Calling it a framework simply because it calls your code would miss that distinction.
An application can combine a UI library with routing, data access, build tooling, and other conventions. The resulting stack may behave much like a framework from the team's point of view, even when each selected package has a narrower description.
For comparing particular JavaScript options, see the React, Vue, and Angular comparison.
Freedom Comes with Integration Work
With separate libraries, you may be able to replace one capability without changing the whole application structure. That freedom can help when you're fitting new code into an existing system or working with an unusual constraint.
You also own the connections between those libraries. Somebody must decide how their conventions fit together, how shared state crosses boundaries, and how upgrades are tested. Each library can be perfectly reasonable on its own and still awkward to use with the others.
A framework can make some of those decisions consistently and provide a documented path through common tasks. That can reduce the amount of local infrastructure a team needs to invent. It can also make work awkward when the product's requirements don't fit the assumptions built into that path.
I wouldn't call either arrangement automatically simpler. You still need to understand the work a framework does for you, or maintain the connections you've made yourself.
Size and Popularity Don't Settle the Category
A library can be large, and a framework can be relatively small. A popular tool can impose very few conventions, whilst a small internal framework can dictate an entire team's application structure. Download size and adoption figures answer different questions.
"Opinionated" doesn't settle it either. A library can enforce a strict data model or naming convention within its area. A framework can expose several ways to implement an extension point. The useful detail is which choices are constrained and whether those constraints fit the work.
Before adopting either, I'd want to see how a feature is registered, how failures are handled, and how to test the result. I'd also want to know what I'd have to change if we replaced it.