Hacker News new | past | comments | ask | show | jobs | submit login
How we use web components (github.blog)
260 points by prakhargurunani 8 months ago | hide | past | favorite | 80 comments

I’ve been using webcomponents heavily in my latest project. Built out a full SPA using vanilla js. They are not without problems, but GitHub is using them perfectly. GitHub isn’t pushing them to do what they aren’t yet good at. They’re amazingly suited for consistent components, especially view oriented ones. GitHub also has in my opinion made the correct choice to make their own base element rather than using a standard library one like lit-html. A good base element has two things in my mind - styled component functions and shared util functions specific to your app. It’s amazingly easy to make a simple set of styled component base functions. Here’s the one I made for my project: https://github.com/jjcm/soci-frontend/blob/master/components... (lines 6-32 for the styled component functions). The rest of your component should be shared functions specific to your use case. Once that base class is there they’re so easy to use.

Two caveats with webcomponents however. The first is Safari will be the bane of your existence. You should dev in safari if you can. If it works there it will work in all other browsers. The second is stay away from form elements, for now. Or if you do, use an encapsulating component that inserts a slotted input into the light dom. The form registration api isn’t fully supported yet except by chrome, and even then it’s a bit rough around the edges.

WebComponents are an amazing replacement for jQuery, get the best of frontend Component based development without the bloat and the JS toolchain! Vanilla JS is great with WebComponents. We even write them in python with Ryzom's transpiler:


class DeleteButton(Component): tag = 'delete-button'

    class HTMLElement:
        def connectedCallback(self):
            this.addEventListener('click', this.delete.bind(this))

        async def delete(self, event):
            csrf = document.querySelector('[name="csrfmiddlewaretoken"]')
            await fetch(this.attributes['delete-url'].value, {
                method: 'delete',
                headers: {'X-CSRFTOKEN': csrf.value},
                redirect: 'manual',
            }).then(lambda response: print(response))

Speaking of which, Rails ViewComponent looks a lot like Python Ryzom, except the later optionnaly supports data-binding over websockets.

But writing JS in Python is extremely satisfying if you already like writing Python more than you like writing JS ;)

as someone who regularly works w python and javascript and misses being able to just write some simple html, this code snippet is going to give me nightmares...

i assume any linter for this code will one day become sentient.

For my sideproject (https://profilehunt.net) I have been using a somewhat similar approach. I use Github ViewComponents (https://github.com/github/view_component) for componentization of Rails views. It helps with more modular views which are easier to debug (errors usually point directly to the line in view code, unlike Rails views). I use StimulusJS (https://stimulus.hotwire.dev/) for Javascript interactivity. Stimulus is great, it allows me to write more structured reusable JS controllers without global event listeners and ids. For my project I have heavily used these two to create a Trello like board which behaves like an SPA. State and routing is still on server. I just fetch HTML on clicks and render it using Stimulus. It is usually fast enough as I only fetch small components and append them to DOM, but in case it's not I use loading animations. If you want to take a look at how it is done, this blog post (https://boringrails.com/articles/hovercards-stimulus/) explains it really well.

edit: Fixed a link and grammar.

I am still wondering if ViewComponent will ever officially make it into Rails.

It is very easy to add. Rails 6.1 introduced a way to use the m without a monkeypatch (https://github.com/rails/rails/pull/36388). But yeah having them natively inside Rails will help with greater adoption of components into Rails way.

Generally speaking having a default way ( or option within default ) of doing things in Rails make things a lot easier for newcomer and maintenance.

I sort of wish Rails is more of Github's Rails rather than Basecamp's rails.

How do u append stuff to the DOM, new Hotwire or Rails ujs?

Clicking on buttons triggers Ajax request via stimulus controller (this takes care of CSRF and session) and fetches just the required HTML from route and appends using innerHTML (https://developer.mozilla.org/en-US/docs/Web/API/Element/inn...).

an example following is an event listener in a JS controller.

  openAddJob(event) {
    this.modalPanelTarget.innerHTML = MODAL_SPINNER_HTML;
      type: "GET",
      url: `/job_items/new_form`,
      success: function (repsonse) {
        this.modalPanelTarget.innerHTML = repsonse;
      error: function (repsonse) {},

Currently there is a lot of scope for DRY a lot of things in the app but will be doing that once I have more feature tests coverage.

OK you kinda roll your own solution here, looks easy enough.

I was really excited about web components until I discovered that slots and CSS isolation are a package deal.

Absolutely great for the developer that wants to ship pre-built components that cannot be affected by the CSS of the site they're used in; absolutely useless when you want to make re-usable components for your own app, where you very much want slot content to be styled using the CSS you already have.

CSS variables help somewhat with this. Variable values penetrate the shadowroot, so you can effectively build an "api" for styles your component. I've done that a few times, and it's been enough for me to get by in most cases. An example is here: https://github.com/jjcm/soci-frontend/blob/master/components...

Take a look at CSS shadow parts. It allows you to mark which part of the shadow dom are stylable which you can then access using the ::part() pseudo element.

Another handy thing to know is that exportparts reexports parts from a nested web component, and CSS --custom-properties will cascade down into the shadow dom


I didn't know about that and it is certainly interesting, however for my particular use case it wouldn't have worked unfortunately. I was using Tailwind, so rather than targeting specific components from a global style sheet, I was trying to use the utility classes from the global sheet inside a web component.

Ahh yes. I believe the tailwind workflow is incompatible with the component scoped styles which web component forces. I believe however that when you use components scoped styles (whether through the shadow dom, React’s styled components, Vue’s single file components, etc) tailwind becomes obsolete (or rather the wrong tool for the job).

You can link to your main css from within the component. Browsers are smart enough to use the cached css file.

Interesting! I had not considered that.

I don't suppose you know if there's any performance impact there—e.g. even if it's not downloading it, is there overhead from processing the file once per component?

I'm not sure, but I haven't had any performance problems (including some performance score tests), even in larger projects.

I do pretty much everything with Web Components these days.

It's so nice to be able to pick things I need from different frameworks, like Ionic, vaadin, Shoelace, etc... and they all just work together.

I tend to implement vanilla web components, I enjoy managing the life cycle and don't find it particularly burdensome. Of course. Lit-html is a big reason why that's easy to do. I use it for rendering. I generally avoid using the shadow dom unless I have a really good reason.

My components all self-register, and are pretty encapsulated. They all maintain internal state, but for more global state I use a library I wrote called ApplicationState [1].

It's hard to imagine going back to the framework churn after experiencing the freedom of Web Components.

It really feels like we've finally realized the promise of composability, reusability, encapsulation and performance with Web Components.

[1] https://claytongulick.github.io/applicationstate/

I don't know if it's on purpose, but ApplicationState is a lot like Redux, except the action dispatching mechanism has been replaced with setting state properties directly. I'd still prefer the dispatch mechanism since it means you can have additional, reusable logic in the reducer.

Its design was specifically intended to avoid the extra code involved in dispatching.

There are also some other goodies in there like aliasing that I enjoy.

I'm currently working on testing a UI with Selenium that uses Shadow DOM all over the place. It's hot garbage, and I have no idea why anybody thought this was a good idea.

Something goes wrong in CI and you'd like to dump the DOM to figure out why? Too bad, the entire page is sitting inside a Shadow DOM, and you get to see an empty body tag and a timeout waiting for an element to appear.

Want to click that button that's nested 5 Shadow DOMs deep? Have fun creating a monster JS query to manually trawl though the Shadow DOMs to click it, because Selenium has no idea how to access the button. And that's if you're lucky and the Shadow DOM is marked "open". If it's marked closed, you can go sit on your thumb.

It's like someone looked at iframes and thought "hey, that's a great idea!" and never stopped to think why they were considered bad practice already 20 years ago.

It's surprising how poorly supported Shadow DOM is across the major UI testing frameworks. To access a Shadow DOM element you'll typically need to write a JS shim that uses the DOM APIs to get at the element, and then do other tricks to work around things like closed vs. open shadow roots and handle how event propagation works with shadow DOM.

Shameless plug, but we're building a no-code testing framework (https://reflect.run) that does all of this for you automatically. Works great with Shadow DOM (both open and closed) as well as more esoteric things - for example did you know Salesforce's Lightning framework overrides how Shadow DOM works? :D

That looks cool, but from what I can tell, not really something I can use. All of the Selenium testing I'm doing is accessed via localhost, often on bare metal. None of it's available via the internet, which it looks like is required by your service.

I don't really how you took a bug in Selenium and somehow turned it into an indictment of Shadow DOM.

It's not just Selenium, it's anything that has to interact with Shadow DOM. If you want to use pure JS to click the button in my above example, you can't just write this:

You have to write something like this:

It's not just the length of the query (which can get stupidly long), it's that you have to know and care about the overall structure of the document and where the button sits in it. I just want to click the damn button. It has a nice, easy-to-find ID attached to it, why does that have to be so hard?

Also, it's not a Selenium bug that you can't dump the entire DOM when Shadow DOM gets involved. That's by design; Selenium just allows you to call `innerHTML` or similar, and if the <body> tag is using Shadow DOM because someone else thought it was a great idea to make the whole page a Web Component then you're SOL and you'll just get `<body></body>`. Have fun debugging that.

The worst part about all this bad design is that it wasn't even necessary. Are you worried about a bad CSS rule from some fancy component causing havoc with the rest of your page? There should exist something as simple as `<div style-link="foo.css">...</div>`. Have those rules scoped to that div element and you're done, problem solved. Worried about some component's JS causing havoc? Same thing, `<div script-link="foo.js">...</div>`. All JS is automatically scoped to that div element. That would have been far better than the brain-dead approach of Shadow DOM.

IMO the shadow DOM should be used sparingly and in most cases not at all.

You can use web components without the shadow DOM (I've seen them being called "custom elements" then). That's what I do and I'm happy with the results.

"Web components" is really a collection of several independent specifications. Custom elements and shadow Dom are two of those, and I tend to agree that sticking with just custom elements will save a lot of headaches with the way things are now.

Would love to see why they did not choose lit-element, it was one of the best I tried in a recent experiment of ~5 libs.

The big thing holding back webcompinents at this point is a data sharing strategy, and I think we could get away with actually using components to store and manage data:


The github repo (which also happens to contain how to write a web component in lit-element, slim.js, tonic, vue, svelte):


> Would love to see why they did not choose lit-element

Most likely explanation: It simply didn't exist yet when they chose.

Also, lit-element requires elements use its own base class while Catalyst doesn't.

I think when they released Catalyst Lit was still in beta

At my work web components were purposed recently for creating a ui component library of which I was skeptical. On the whole I was skeptical of web components viability and future but this post relieves some of that tension.

The other thing I was worried about was that it was planned to after writing this web component lib, to wrap these components in React. Does anyone have any experience or insights into a React wrapped web component lib?

The Lit team has a labs project called @lit-labs/react that will automatically create a react wrapper:


It works alright with React if you treat it like regular DOM elements, but there's rough edges like SSR event handlers not working: https://github.com/facebook/react/issues/18390

Unfortunately it seems facebook isn't prioritizing fixing issues like this.

I'd suggest using preact if you want a framework that's more compatible with web components but gives you the React experience.

Super easy to incorporate with React. Just use react to pass attributes, like so:

    class App extends React.Component {
      render() {
        return (
          <my-component custom-attribute={value}></my-component>
In your webcomponent just make sure you listen to changes to that attribute like so:

    static get observedAttributes() {
      return ['custom-attribute']
Then you can decide how the component changes whenever that attribute is updated by using the `attributeChangedCallback` function. Alternatively, use a base element that incorporates a render() function which will automatically update everything in the shadowdom.

Main difference is it becomes much harder to pass complex data structures. Passing strings is easy, but passing an array of data isn't feasible with this model.

Issues arise when trying to pass objects or add event listeners for custom events due to how React specifically handles this stuff. You often have to use refs

And even refs aren't enough if the custom element does its initial render asynchronously. I had to add mutation observers to some wrappers to avoid polling the ref.current.

Wrapping React components in Web Components has limits you'll quickly hit. Suppose you have two components (in a parent/child relationship) that share context (e.g., you're wrapping react-beautiful-dnd in Web Components-- <Draggable /> and <Droppable />). Each component has it's own ReactDOM.render call, and therefore is its own React VDOM tree with no shared context.

So you can't take existing React libraries and 1:1 map them to web components. That approach only works for 'leaf' components that accept no children.

In a closed source project I worked for, we used wrapped web components as React components for a UI library. I cannot show something here, only the approach we have used for it: https://www.robinwieruch.de/react-web-components

I've refreshed myself on web components, templates and shadow DOM, and I understand how each of them works, but I only see immediate benefits from templates. The rest seems a bit like abstraction for abstraction's sake and syntax sugar over existing capabilities.

What am I missing, what's the elevator pitch for web-components and shadow DOM?

Scoped styles seems to be something that's pushed with shadow DOM a lot, but isn't <style> in the page body illegal HTML (despite yes, it works)?

The benefit is scoped everything (styles, JS, templates). So that when your site grows, and you start erasing functionality because you created something better, you can actually erase the entire functionality with confidence, and not have some stuff hanging around because nobody is sure what it's used for.

I have personally not built anything for the web using components, so I don't know how much they satisfy that promise in reality. But that's the promise.

In some ways, it still isn't great. You can't create font rules in CSS in shadow DOM; they are ignored.

WC + Shadow DOM are great for using 'new' components in, say, a legacy web application that has leaky style rules (e.g., the main app has style selectors like `button`), which would bleed into your new component.

I'm wondering about the elevator pitch too. Honestly it seems like github went through all this trouble just because they don't want to commit to a framework like react.

Still having a tough time seeing the benefits of web components.

I find it odd that people compare React and web-components a lot. Sure, superficially both have custom components. But why does that matter even?

To me React's value is JSX and ReactDOM. I actually use JSX+ReactDOM without the rest of React, using basic classes. Works great.

> What am I missing, what's the elevator pitch for web-components and shadow DOM?

There's none except the oft-repeated "use the platform!" (as if other frameworks and libraries use something else, and not the platform).

Currently web components work, if:

- you have a large distributed team, and

- you need to have consistent elements and styling across many properties, and

- your components can be expressed as "leaf elements". That is, view-only elements. No forms, no state, only presenting some data.

Beyond that the elevator pitch is "for the past 10 years, and counting, we've been bravely trying to fix the ever-growing list of problems that web components introduced by simply being. And we're solving that by throwing more and more javascript at the problem".

A very non-exhaustive list: https://twitter.com/rich_harris/status/1198332398561353728?l...

And things like participation in forms? It's "solved" by adding Javascript: https://web.dev/more-capable-form-controls/

Which is ironic, given that the original pitch was "we're piling more and more into Javascript, and we shouldn't" https://fronteers.nl/congres/2011/sessions/web-components-an...:

--- start quote ---

I think we’re stuck today in a little bit of a rut of extensibility. We wind up leaning on JavaScript to get things, because it is the Turing complete language in our environment. It is the only thing that can give us an answer when CSS and HTML fail us. So we wind up piling ourselves into the JavaScript boat. We keep piling into the JavaScript boat.

Bruce yesterday brought up the great example of an empty body tag, and sort of this pathological case of piling yourself into the JavaScript boat, where you wind up then having to go recreate all of the stuff that the browser was going to do more or less for you if you’d sent markup down the wire in order to get back to the same value that was going to be provided to you if you’d done it in markup. But you did it for a good reason. Gmail has an empty body tag, not because it’s stupid. Gmail does that because that’s how you can actually deliver the functionality of Gmail in a way that’s both meaningful and reliable and maintainable. You wind up putting all of your bets, all of your eggs, into the JavaScript basket.

--- end quote ---

For those who have used tools like Hotwire, what has your experience been like? How does it compare to something like Vue or React?

I've just started using it on a fairly simple project so I only have first impressions. But it seems like for a UI that's not too complex it could be a big timesaver. I need to spend more time with it before I can decide where I'd draw the line and switch to a full blown SPA but it definitely expands the class of apps you can build without much JS.

State management on the front end? Is that the differentiator that forces the need for a full SPA framework? Anything else that can't be done purely with web components?

I think the only state management that really requires SPA is of course the state between pages.

But why actually have pages - I actually think this is a good differentiator of if your site is naturally an SPA or not - if you really need pages, perhaps because people need to be able to bookmark a specific part of your site that is more important to them than other parts - your site as a whole might not actually need to be an SPA although it might have parts of it that function as SPAs.

I'm sure there are people much better qualified to answer this than me but it feels like there would be a point at which trying to manage a very complex UI with all these little HTML fragments over the wire would get unmanageable. I'm just guessing though. So far I haven't done anything that complex with it. I guess I'd also miss having Typescript for a UI with a lot of components.

You can do some client-side state management with Stimulus though.

They aren't really comparable I think, you should compare Hotwire to old Turbolinks + Rails/ujs. Hotwire will make it feel like a SPA but it is not a SPA. Probably for many websites this is enough, but I wouldn't write a computer game with Hotwire.

I've used it (as side project) for a fairly interactive application (https://audiotrails.io). I'm also in the middle of rewriting it with htmx, which offers more features & a larger mindshare/future outside of the Rails community. In addition, I used Stimulus (with turbo) and Alpine (with htmx) where more intricate JS actions where needed, for example the audio player, with Tailwind for the CSS, and Django backend.

I can offer some comparisons with Vue which I have more experience with. I'd describe myself primarily as a backend developer with some frontend experience.

In both cases I found it much more productive than building the traditional SPA. Building an SPA feels very much like building two applications: your backend API and the frontend app. This might make sense where you have a team of specialists, or multiple frontends (i.e. IOS+Android+web). If you're a sole developer it's important to acquire "superpowers" that give you a productivity boost to compensate for your limited time and expertise, and Hotwire and htmx feel very much like superpowers. Combined with a compatible JS library like Stimulus or Alpine I didn't feel like I hit too many walls compared to Vue. This made it easier to focus on the UI and backend logic and kept maintenance to a minimum.

That said, the more interactive parts did require some lateral thinking where Vue would have likely been easier in terms of the mental model, for example keeping an audio player open during page navigations and maintaining state without full page refreshes (i.e. to prevent the player restarting). Another thing I missed where the sheer ease of building and re-using components in Vue, and Django templates and tags feel quite clunky in comparison (some other frameworks like Laravel have perhaps a better template component model). Overall though it was so much easier to build a traditional web application compared to the complexity of an SPA.

Comparing Hotwire to htmx: Hotwire required more server work when doing atomic changes (HTML fragments returned from AJAX requests). There's an existing Rails gem which does most of this, I had to write my own Django package. There's an expectation that it should be used with websockets, but really that's optional. In most cases though Turbo Drive works pretty much like Turbolinks: once you install it, it will provide SPA-like page transitions for free. Htmx feels a bit less polished, and the learning curve is a bit steeper, but has much more in the way of features and extensions and doesn't require as much rework in the backend. There's an hx-boost feature that works similar to turbo drive but I found it's easier to use htmx' low-level options to manage different sections of the site as appropriate.

We've started converting everything to web components using Stencil. Allows us flexibility to have the same look and feel no matter what framework we're using.

Took a minute to figure out how to get React/Vue components to render inside of a web component, but now we're all set.

I have a very dumb question. I'm currently trying to implement web components into a pretty basic flask site, and I'm really having trouble. Does anyone know any resources about basic implementation that I can review?

I was interested in Lit, and am try to bundle that, but it's not working at all, and I really feel like I'm missing something.

Check out https://open-wc.org/

Especially their code examples

thank you for this

You can get lit-specific advice on their Slack. The link is on their docs site

yes, thank you, it seems i'm not the only one asking this question there

I started using ficusjs for some experiments [2]. I built a signature button for Metamask [1].

What's great is that:

- I use preact's htm as a renderer [3], which is JSX but as template strings.

- The API is like (p)react but a bit more generalized. I like it.

- The web component concept is great. Especially for mixing server-side rendering and JavaScript-powered components.

That last one IMO is web components killer feature. I can now wrote a mini component and then I tugg it in with the other 99% of my page that is rendered server side.

It means, I'm able to serve my users quickly. I have SEO'd everything too. Cool!

-1: https://github.com/TimDaub/web3-sign-msg

- 2: https://docs.ficusjs.org/

-3: https://github.com/developit/htm

As far as server-side rendering, is that any different than react server-side rendering?

In my side project I use Vue CLI's async webcomponents target to generate a webcomponents.js can be imported into a script tag and <some-element props="123"/>. I was at a loss how to include compiled SFCs (components) into a server rendered app. IME, Vue tooling assumes a Node JAMstack SPA and the Django boilerplates were a pain. Guys who wanted to sprinkle interactivity to their apps were at a loss.

Something I've never understood how to handle with vanilla web components: if there's some state that needs to be shared and kept in sync between multiple components, how do you do it?

(For comparison, in React you can pass the state down as props from a common ancestor, and in Clojure frameworks all app state is in a giant object referenced by components as needed.)

The nice thing about web components, is that this problem is orthogonal go the componentization of the components.

How do you pass the state between an input button and a label?

Whatever technique you choose to do that (including react!) you can use it with web components.

Some frameworks like react though also solve the componentization problem, so since web components are not necessary there (and weren't ready yet when react first came out), they tend to not get used to react and friends, even if they would technically work.

For passing upwards I typically fire a custom event, with data in the detail field. For passing downwards, I have the parent delegate attribute changes on the children as much as possible. This limits you to only passing string values downwards, but it keeps the html mirrored to the state, which has a simplicity to it that I prefer.

An example of this would be a radio-group and radio-element. When an element is clicked it fires a "clicked" event to the parent radio-group. The radio-group then toggles on "selected" for the clicked element, and removes the previously selected element's "selected" attribute.

So basically, the answer is to do it how you did before (shared global state or events etc)

I recently took the time to explore a new idea I haven’t seen explored before —- services as DOM elements:


Straight to the repo:


The idea is simple, use references to get at other DOM elements that happen to act like whatever kind of store you need

You just addEventListenner on change or input and update your state. Nothing special here.

How well do web components work in the context of SEO and pagespeed scores?

I’ve had mixed results. Page speed is excellent - I built out an SPA with ~60 or so components and my uncached first paint happens in about 400ms. Cached I get 250ms (this is on prod so it includes the server latency). SEO is more difficult. I’ve been using the npm package prerender to serve up the page properly for Google/Facebook/Discord bots and for crawlers, and since using that I’ve had successful parsing, but at the cost of perceived performance by the bots (the prerender step adds about 2s to the pageload, which only the bots experience).

I’m pretty actively following a lot of the web components community so I thought I would jump in here with some hopefully helpful information. Depending on what you mean by SEO it’s worth noting that for a while now Google and I believe Bing and a few others haven’t had any kind of requirement to pre-render content. You can just serve standard web components or any kind of SPA style front end and it will get indexed just fine, no penalties and no real issues unless you’re doing something particularly strange.

However, one of the more exciting projects in the web components space (lit.dev) now also supports proper SSR as well which is a very new thing in the world of web components. They are trying to build it in such a way that any other library can take advantage of through a common interface.

In fact there are some kind of early stage talks happening over here https://github.com/webcomponents/community-protocols where a bunch of companies like Google, Adobe, ING and others are trying to develop some open protocols on a whole bunch of topics to improve interoperability between various libraries so that no one has to buy in 100% to any one setup.

Why don't you cache the prerender and serve to everyone?

I'm using a static html file for the full app. The client side selectively removes/adds html for each of the pages depending on the url. Upside to this approach is that static = fast. Downside is if I prerender then the routes don't have the initial context for navigation to other pages. The prerender shows only a subset of the full site. I'd have to re-architect the client side router I wrote to support it, and that's very low on my MVP list, especially with performance in the 200-400ms range as it is.

I think they're generally intended for use in SPA/PWAs.

I doubt the shadow dom is particularly crawler friendly.

Also, they aren't great at SSR though some frameworks try to fix that.

It would also depend a lot on how you were using/designing them.

If you were using slots and putting content inside of a custom tag, and just using that tag for display concerns, SEO would be just fine, though you may lose some semantic markup points.

Shadow DOM is crawlable for a few years now

On the topic of web components, does anyone know if AMP is still using them? I heard they switched over to Preact but I couldn't find an official announcement.

You can totally write web components with Preact: https://preactjs.com/guide/v10/web-components/

From a quick skim of their docs, it looks like AMP still uses web components.

The nice part about web components is that the users of a library don't have to care about how it's implemented, so switching to preact is a transparent change.

React still doesn't play seamlessly with WC right?

This site tells you which frameworks work well with custom elements. And if they play well with custom elements, then they're usually fine with web components


It seems to work okay as in you can use them: https://reactjs.org/docs/web-components.html

But it is not fully integrated with react, you have to do some work for interaction: https://www.sitepen.com/blog/wrapping-web-components-with-re...

That link is a few years old though I think the principle is the same.

51 comments and no mention of Stencil? hmm.

"At GitHub, we pride ourselves on delivering a first-class developer experience."

Ugh, every time I see such PR-ese language, I want to stop reading any further

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact