Modernizing Meteor ideas: an official UI elements library

People are talking about “Making Meteor great again”. I’d like to think of it as making it even greater!

So here’s another idea. It was mentioned there that a one-way-of-doing-everything solution would be great, but that being able to replace or remove any piece of the stack is also great.

To that end, having an official Meteor UI library of themeable Custom Elements would be awesome.

  • What could be included? Examples of custom elements (with a mtr prefix for “meteor”, it is a convention with custom elements for libraries to use a certain prefix to avoid name collisions, plus a hyphen is required in the name of a custom element):
    • <user-profile> to show user information in a visually organized way out of the box. It would be responsive, so it would fit in a small area (such as a card) or on a full-width page to show user profiles
    • <login-buttons> (the accounts-ui Blaze component as a Custom Element)
    • Perhaps, if Meteor adds an official package for site stats, then elements could include charts, graphs, etc.
    • generic components for UX:
      • <mtr-button>
      • <mtr-tab-bar>
      • <mtr-tab>
      • <mtr-range>
      • <mtr-select>
      • <mtr-split-panel>
      • <mtr-color-picker>
      • <mtr-calendar>
      • etc
  • These elements would work in any framework including React, Vue, Svelte, Solid.js, including with type checking and intellisense. Devs bring their framework, Meteor provides the default set of UI elements.

The idea is that Meteor users would have the best way to build full stack apps out of the box. Everything they need all ready to go. Right now, in terms of UI/UX, there is not very much offered by Meteor so people need to install external libraries or make their own.

1 Like

I guess a question as a Meteor user is what we would want eg mtr-button to do. Especially if teams are using ionic + Cordova (or, optimistically, one day, capacitor), or already happy with something else.

The feeling I get is generally a lot of teams have trouble migrating off of component libraries that are tightly coupled to one UI framework eg Chakra, Vuetify, etc; thus the current popularity of Tailwind.

But something I like is what PicoCSS (and in another way, DaisyUI) do, where they start you off with a fairly opinionated CSS-based approach to having a prestyled component library, ala Bootstrap, and you customise from there; but often you do need to pair them with a UI framework specific “headless” component library like Headless UI or Radix UI.

Edit: to clarify, other components have a more obvious purpose IMO. Like “login button”, things that’d normally use a blaze template, etc, those have a more immediately obvious value proposition

The nice thing about Custom Elements (or plain CSS when an element is not needed) is that this can be transferred to any app, or any framework.

As a user of Meteor, I would like it if, for example, Meteor has its own UI custom elements similar to Shoelace:

This would mean that, out of the box, Meteor users would be able to develop apps with a whole UX library without having to intall anything. Some of these elements would even be reactively connected to Meteor’s backend features such as accounts, etc.

This would also mean that a set of Meteor users have a conventionalized set of UI elements to work with, making it easier to create plugins on top of that UI library, and share it in the Meteor community more easily. For example, someone could write new elements for an admin dashboard which would work with default meteor apps in a way that standardized in Meteor, and users would be able to easily customize the dashboard using standard elements.

Not that any of this is not possible to build in the form of 3rd-party UI libraries, but doing it as a 3rd-party-only approach makes the community a little less interconnected.

In the early days of Meteor, when there was only one way to do everything, and extensions to Meteor were all on Blaze, it was easier to cobble things together.

The idea here is that Meteor could take things to a higher level, making it easier for plugins that add UI/UX to be standardized on Meteor (rather than everyone trying to make different extensions for different UI libraries).

Note, Blaze is not a UI library, but a UI component system. Meteor never had an official UI element library. If it did have on written on Blaze, that would not be so great because then those elements would not be usable by users who want to use React/Vue/Svelte/etc.

By virtue of this hypothetical UI library being built as Custom Elements, any Meteor user could still use the official UI elements with React, Vue, Svelte, Blaze, and all other UI component systems.


All the pieces of Meteor would be replaceable. If someone wants to remove the package(s) that provide Meteor’s official UI elements, they very well could, and they could still build their own or import from 3rd-party libraries.

2 Likes

Oh, it looks like Shoelace has come a long way - it’s definitely quite compelling. Maybe something I’d migrate to one day. I was wondering maybe if it’d be good to use an existing library like that but I can see a potential issue - they’re about to change it to “Web Awesome” so then that’d be a breaking change on the horizon for Meteor which is not ideal. Dealing with Node breaking changes is not so bad but frontend libs tend to be quite volatile.

Given that I can see more justification for having a Meteor specific library.

I think it’d be the cherry on top of the icing on the cake if it could be somehow usable in non-Meteor projects too, just without Meteor specific functionality. Because one issue for example I’d have with using other high quality but framework specific UI libraries like Nuxt UI is that you have to keep using Nuxt, if you move away from Nuxt you’d also lose your entire frontend.

But I’m biased because I have one project that’s migrating from Meteor to Nest, gradually, so I need to keep that in mind (and I have some trauma from my Meteor v3 + Vue v3 + Vuetify v3 migration). And I guess Meteor has to serve its own community first; fence sitters like me should know better and plan ahead :sweat_smile:

Otherwise much more sold on the idea now.

1 Like

The problem is really that by installing Shoelace or one of many other UI libraries that aren’t renaming, then we’ve just installed one of many UI libraries rather than something standard for the Meteor community to rely on.

The win here would be that if Meteor had something official, then there’d be a standard that people using Meteor could rely on for building on, plus Meteor would be able to build its own features to make development of interactive apps easier out of the box.

Right now we have to go find 3rd-party solutions, and we all end up doing it in various way that are not conducive to us all building a cohesive ecosystem on top of Meteor. It’s great that we can, if we need to, but having a standard UI in place would be a boon for Meteor frontend.

Oh yeah, definitely, and it would be totally doable that way. For example it would be like writing Lit, Fast, or Lume Element (my own), or even using one of those, or even adopting Shoelace for that matter, and people would be able to npm install them outside of Meteor, so long as the solution would be an official selection by the Meteor team, in a way such that whatever Meteor builds with it is automatically compatible with all other frameworks.

I may be biased, but I think Lume Element is the most advanced for this use case because I haven’t seen any other Custom Element framework release cross-framework type definitions yet, Lume Element is the first to have this (custom element framework authors, please “borrow” the approach!).

1 Like

Just a note for readers in the future @trusktr made a related topic to this that explores this a bit further:

I’m very much in favor of exploring this. Would really love to bring back the days of rapid prototyping and expand it to other feature rich packages like socialize (@copleykj). Then they could be made easily themable and as things advance the components would be more optimized for larger deployments.

But something in my memory is telling me that there was some issue with Web Components in Meteor. Not sure what, but I wonder if that was resolved already.

1 Like

@trusktr what do you think of a blaze port for radix ui?

I recently published blazeui which is a mimic of shaven/ui but the components are already styled. I could also think of making a move to an unstyled version of it

1 Like

No issues at all (at least not anything more than integrating React, Vue, Svelte, or any other component system). At the very least, they work in plain JS without a build, but integrating them into Meteor current build would enable server-side rendering for them just as with React/Vue/etc.

Example: right-click inspect element on the graphic here

to see <lume-*> elements, or in the code editor here,

to see <live-code> and <code-mirror> elements that create the text editor and live preview. (It’s two clients connected to one Meteor backend).

There isn’t really anything about Meteor that prevents custom element usage. Depending on which Custom Element framework is being used, some code does need to be written to connect Meteor reactive vars to the custom element’s reactivity system, just as with React/Vue/Solid/etc.

For example, with Meteor and Lume Element (built on Solid.js) it may look like this:

import {Element, element, stringAttribute} from '@lume/element'
import {getOwner, onCleanup, createSignal} from 'solid-js'
import {Tracker} from 'meteor/tracker'

const author = new ReactiveVar('jkuester')
const getAuthorBooks = author => Books.find({author}).fetch()

// This would be in another file for reusability, but here for now:
export function toSolidjsSignal(meteorGetter) {
	const [get, set] = createSignal(meteorGetter())
	const comp = Tracker.autorun(() => set(meteorGetter()))
	if (getOwner()) onCleanup(() => comp.stop())
	return get
}

// (for cross-framework type definitions further below)
export type AuthorBooksAttributes = 'author'

@element('author-books')
export class AuthorBooks extends Element {
  @stringAttribute author = 'trusktr'

  // Turn the Meteor reactive expression into a Solid signal for use in Solid effects.
  // Any time `author.get()` changes, the Solid signals will end up changing.
  #authorBooks = toSolidjsSignal(() => getAuthorBooks(author.get()))

  template = () => html`
    <ol class="authorBooks">
      Author books: ${() => this.#authorBooks.map(book => html`
        <li>
          Title: ${book.title}<br />
          Pages: ${book.pages}
        </li>
      `)}
    </ol>
  `
}

// Register the type for DOM APIs in TypeScript.
declare global {
	interface HTMLElementTagNameMap {
		'author-books': AuthorBooks
	}
}
<!-- In another element's template, or in an HTML file: -->
<author-books author="storyteller"></author-books>

Let’s pretend that the <author-books> element is part of Meteor’s UI library for a moment. In separate files Meteor would add type definitions for other frameworks. Here for example is the type definition for React:

import {AuthorBooks, AuthorBooksAttributes} from '.../author-books.js'
import {ReactElementAttributes} from '@lume/element/dist/framework-types/react'

declare module 'react' {
	namespace JSX {
		interface IntrinsicElements {
			'author-books': ReactElementAttributes<AuthorBooks, AuthorBooksAttributes>
		}
	}
}

And for Svelte it looks like this:

import {AuthorBooks, AuthorBooksAttributes} from '.../author-books.js'
import {SvelteElementAttributes} from '@lume/element/dist/framework-types/svelte'

declare module 'svelte/elements' {
	interface SvelteHTMLElements {
		'author-books': SvelteElementAttributes<AuthorBooks, AuthorBooksAttributes>
	}
}

And voila, custom element that has IDE type checking and intellisense no matter which framework a Meteor is written with.

1 Like

I think a Custom Element port would be much more valuable. The OP and the content of this comment above shows, for example, how to define a custom element with Lume Element, with type definitions across frameworks.

A Blaze port would be limited to Blaze users as opposed to being useful for all Meteor users regardless of framework.

EDIT: Oh! I got confused, I thought you meant Blaze as we’re here talking about Meteor! You mean Blaze! :smiley: Yes, this is definitely on the right path. Something like this indeed. Personally I don’t like Stencil very much because the classes are not the element classes themselves, but as a user of a hypothetical Meteor UI library, I wouldn’t really care what the elements are written with (heck, they could be written with React underneath) so long as I can use them, with type checking in my IDE for my framework’s templating, and without a build step being required (I see the BlazeUI examples import code from CDN which indicates the elements are already compiled for plain JS).


@storyteller @jkuester besides the above, a framework like Meteor could also have a cross-framework server-side rendering (SSR) and static site generation (SSG) story like Astro.

Astro has the ability to allow any component system (React/Vue/Svelte/Solid/Lit/etc) to be used in a full stack includin SSR and SSG support regardless of the chosen component system.

Another awesome example of cross-framework SSR/SSG, but only for custom elements, is Greenwood. This wouldn’t be an ideal path for Meteor if it wants to support SSR/SSG for all the non-custom-element frameworks too. But nice to see how they’ve done it for inspiration.

1 Like