docs/blog/introducing-apollo-elements/index.md
---
title: Announcing Apollo Elements
published: true
date: 2019-01-16
updated: Last Modified
description: Create web components that leverage the power of Apollo GraphQL.
tags:
- webcomponents
- graphql
- apollo
- opensource
cover_image: https://thepracticaldev.s3.amazonaws.com/i/rk6u6o9jibsv4vo3cpgb.png
socialMediaImage: https://thepracticaldev.s3.amazonaws.com/i/rk6u6o9jibsv4vo3cpgb.png
---
<sup dir="rtl"><abbr title="בסייעתא דשמייא">בס״ד</abbr></sup>
Today I published version 0.0.1 of `apollo-elements`, a collection of packages that help you create web components connected to {% footnoteref "apollo" "Apollo Elements is a community project maintained by myself, it's not affiliated with Meteor." %}Apollo GraphQL{% endfootnoteref %}.
{% github apollo-elements/apollo-elements %}
Apollo Elements handles the plumbing between web components libraries like `lit-element` or `hybrids` and Apollo Client, so you can concentrate on building your app.
If you're new to web components, take a <abbr title="peek">👀</abbr> at my "Let's Build Web Components" series to get up to speed:
{% dev https://dev.to/bennypowers/lets-build-web-components-part-1-the-standards-3e85 %}
## Connected Components
In a component-based app, each component can derive its state from some separate state storage. For example, you can create components which connect to a Redux or MobX store and subscribe to changes to their piece of the state puzzle.
GraphQL's flexible and extensible syntax is a natural fit for component based design, and Apollo's powerful implementation lets us easily make the connection between GraphQL data and our components. Using `apollo-link-state`, you can even get rid of client-side state containers like redux altogether and *query your entire component state from the apollo cache*.
```graphql
query UserProfilePage($userId: ID) {
session @client {
token
expiresAt
id
}
user(id: $id) {
name
avatar
friends {
name
id
}
}
}
```
## Show Me The Code
Now, with Apollo Elements, you can get up and running building connected components. You provide a GraphQL document and a custom element {% footnoteref "hybrids-class" "Or in the case of hybrids, all you need is a render function." %}class{% endfootnoteref %} that handles templating, and you're good to go.
```js
import { ApolloQuery, html } from '@apollo-elements/lit-apollo';
// A component that uses ApolloSubscription to update
// when users go on or offline.
import './user-online-status.js';
import './loading-spinner.js';
/**
* `<user-profile-page>` Shows a user's profile, as well as a list
* of their friends which display's each one's online status via a
* GraphQL subscription.
* @extends ApolloQuery
*/
class UserProfilePage extends ApolloQuery {
render() {
const { loading, data } = this;
return (
(loading || !data) ? html`<loading-spinner></loading-spinner>`
!data.user ? : html`<login-form></login-form>`
: html`
<h1>Hello, ${data.user.name}</h1>
<profile-image src="${data.user.avatar}"></profile-image>
<h2>Who's Online?</h2>
<dl>${data.user.friends.map(({id, name}) => html`
<dt>${name}</dt>
<dd><user-online-status id="${id}"></user-online-status></dd>
`)}</dl>
`
);
}
updated() {
// get the currently logged-in user's id from the `@client` query.
const { id } = this.id;
// setting variables updates the query.
if (id) this.variables = { id };
}
}
customElements.define('user-profile-page', UserProfilePage);
```
Once you've added your elements to the page, set their `query` property to a GraphQL document and you're set.
### Inline GraphQL Scripts
You can even do neat little optional tricks like defining your queries declaratively in HTML with inline GraphQL:
```html
<user-profile-page>
<script type="application/graphql">
query UserProfilePage($userId: ID) {
session @client {
token
expiresAt
id
}
user(id: $id) {
name
avatar
friends {
name
id
}
}
}
</script>
</user-profile-page>
```
Cute, right?
## Support for Multiple Web Component Libraries
Apollo Elements grew out of `lit-apollo`, but I wasn't content with supporting a single component class. Version 0 shipped, renamed and rebranded, with support for [`lit-element`](https://dev.to/bennypowers/lets-build-web-components-part-5-litelement-906), [`GluonElement`](https://dev.to/bennypowers/lets-build-web-components-part-6-gluon-27ll), and [`hybrids`](https://dev.to/bennypowers/lets-build-web-components-part-7-hybrids-187l). It also's got some [Polymer](https://dev.to/bennypowers/lets-build-web-components-part-4-polymer-library-4dk2)-style two-way binding elements so you can expose the apollo state in your templates with `{{data}}` syntax.
But the goal here was to give you, the developer, more options. If none of the above are what you're looking for, Apollo Elements also provides [class mixins](http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/) that let you get up and running with any vanilla-like component class, or even good-old-fashioned `HTMLElement`, if you really wanted.
```js
import { ApolloMutationMixin } from '@apollo-elements/mixins';
import gql from 'graphql-tag';
const mutation = gql`
mutation SendMessage($message: String!) {
sendMessage(message: $message) {
message
date
}
}
`;
const template = document.createElement('template');
template.innerHTML = `
<style>
:host([error]) #input {
border: 1px solid red;
}
details {
display: none;
}
:host([error]) details {
display: block;
}
</style>
<label>Message<input id="input"/></label>
<details>
<summary>Error!</summary>
<span id="error"></span>
</details>
`;
class ChatInput extends ApolloMutationMixin(HTMLElement) {
get input() {
return this.shadowRoot && this.shadowRoot.getElementById('input');
}
constructor() {
super();
this.mutation = mutation;
this.onKeyup = this.onKeyup.bind(this);
this.attachShadow({ mode: 'open' })
this.shadowRoot.appendChild(template.content.cloneNode(true))
this.input.addEventListener('keyup', this.onKeyup)
}
onKeyup({ key, target: { value: message } }) {
if (key !== 'Enter') return;
this.variables = { message };
this.mutate();
}
// Override implementation of `onCompleted` if desired.
// Alternatively, use a setter.
onCompleted({ message, date }) {
this.input.value = '';
}
// Override implementation of `onError` if desired.
// Alternatively, use a setter.
onError(error) {
this.setAttribute('error', error);
this.shadowRoot.getElementById('error').textContent =
`Error when sending message: ${ error }`;
}
}
```
Plans are in the works to support even more web component libraries and frameworks in the future, so watch the repo for releases.
So go ahead - install the package which fits your project best:
- [`@apollo-elements/mixins`](https://npmjs.org/package/@apollo-elements/mixins) for class mixins
- [`@apollo-elements/lit-apollo`](https://npmjs.org/package/@apollo-elements/lit-apollo) for lit-element
- [`@apollo-elements/hybrids`](https://npmjs.org/package/@apollo-elements/hybrids) for Hybrids
- [`@apollo-elements/gluon`](https://npmjs.org/package/@apollo-elements/gluon) for Gluon
- [`@apollo-elements/polymer`](https://npmjs.org/package/@apollo-elements/polymer) for Polymer-style notifying elements
## Demo
Want to see it in action? I built a simple chat app demo that uses GraphQL subscriptions and renders it's components using lit-element.
[`#leeway`](https://lit-apollo-subscriptions.herokuapp.com) is a progressive web app that uses `lit-apollo` to make it easier for you to avoid doing actual work. Check out the [source repo](https://gitlab.com/bennyp/demo-lit-apollo-subscriptions) for an example of how to build apps with Apollo Elements. The demo includes:
- <abbr title="server side rendering">SSR</abbr>
- Code Splitting
- Aggressive minification, including `lit-html` template literals
- CSS-in-CSS ( e.g. `import shared from '../shared-styles.css';`)
- GQL-in-GQL ( e.g. `import query from './my-component-query.graphql';`)
- GraphQL Subscriptions over websocket
[![Lighthouse Scores: 98 (performance), 100 (accessibility), 93 (best practises), 100 (SEO), 12/12 (PWA)](https://user-images.githubusercontent.com/1466420/52176144-5c25f280-27b7-11e9-8e14-290651f98e36.png)](https://github.com/apollo-elements/apollo-elements/files/2825459/lit-apollo-subscriptions.herokuapp.com-20190203T132249.zip)
So try out `apollo-elements` today!