How many times have you done this as a front-end developer?
["Pizza", "Pasta", "Ice Cream"].join(", ")
// "Pizza, Pasta, Ice Cream"
Looks fine… until you realize something’s wrong: the final “and” is missing.
So you patch it with slice
, map
, conditionals, maybe even a helper function that grows messier with every project.
But here’s the thing: you shouldn’t be solving this problem at all. There’s already a native API designed for this: Intl.ListFormat.
What Is Intl.ListFormat
?
Intl.ListFormat
is part of the Internationalization API. Its job is simple: turn an array into a human-friendly string that respects language and cultural conventions.
No custom utilities, no edge cases, no spaghetti code.
Styles and Types: Beyond .join()
Unlike .join()
, Intl.ListFormat
gives you control over style, meaning, and locale. Even small differences matter: a comma before “and” (Oxford comma), using “&” instead of “and”, or changing “and” to “or”.
Punctuation Matters: Automatic Commas and Localization
One of the benefits of Intl.ListFormat
is automatic punctuation according to the locale. Small details like commas before “and” (the Oxford comma in American English) or the absence of it in British English are not something you have to implement manually anymore.
For example, in en-US
, the list "Pizza, Pasta, and Ice Cream"
includes the Oxford comma, making it clear and unambiguous. In en-GB
, the same list becomes "Pizza, Pasta and Ice Cream"
, dropping the extra comma as per British conventions.
Even when you use types like unit
or disjunction
, Intl.ListFormat
automatically inserts commas where needed and uses the appropriate conjunction (or none, if the type doesn’t require one). This removes a whole class of small localization bugs that would otherwise require custom logic.
In short, Intl.ListFormat
not only formats the words in a list but also ensures your punctuation matches the expectations of your users’ language, making your app feel more polished and professional.
Examples
const foods = ["Pizza", "Pasta", "Ice Cream"];
// Long + conjunction (default, en-US)
new Intl.ListFormat("en-US", {
style: "long",
type: "conjunction"
}).format(foods);
// "Pizza, Pasta, and Ice Cream"
// Oxford comma before 'and'
// Long + conjunction (en-GB)
new Intl.ListFormat("en-GB", {
style: "long",
type: "conjunction"
}).format(foods);
// "Pizza, Pasta and Ice Cream"
// No Oxford comma in British English
// Short + conjunction
new Intl.ListFormat("en-US", {
style: "short",
type: "conjunction"
}).format(foods);
// "Pizza, Pasta, & Ice Cream"
// Compact style, using "&"
// Long + disjunction
new Intl.ListFormat("en-US", {
style: "long",
type: "disjunction"
}).format(foods);
// "Pizza, Pasta, or Ice Cream"
// Shows "or" instead of "and"
// Unit style (no conjunction, items treated as a unit)
new Intl.ListFormat("en-US", {
type: "unit"
}).format(foods);
// "Pizza, Pasta, Ice Cream"
// Simple comma-separated listing
Notice how small changes in locale, style, or type completely affect the output. These are the details that make lists readable, natural, and culturally correct.
Real-World Use Cases
- E-commerce → “Available in pizza, pasta, & ice cream.”
- Social apps → “Liked by Anna, John, & 3 others.”
- Dynamic lists → When you don’t know in advance how many items will show up.
In all these cases, .join()
falls short. Intl.ListFormat
handles these tiny but important differences for you.
Conclusion
Every time you render a list, you’re not just outputting text — you’re communicating.
And communication lives in details: a comma in the right place, the correct “and” or “or”, a style that feels natural to the user’s language.
Those details are what make your app feel professional instead of hacked together.
To dive deeper into Intl.ListFormat
and explore additional features, visit the official MDN Web Docs. There, you'll find comprehensive documentation and practical examples to help you master this powerful API.
Connect on LinkedIn for more updates and insights.
Top comments (0)