Skip to content

feature: element-based API #25

@trusktr

Description

@trusktr

For example, I think it would be easier to use context with any custom element system regardless of the authoring experience if users could use elements, because all authoring experiences standardize on HTML.

As an example, solid-element allows writing custom elements with function instead of class, so it is impossible to apply a class mixin to a custom element written with solid-element.

However, providing an element-based API would make context fully agnostic of element authoring patterns.

Here's a code sample. This next piece of code is higher up in the tree in some ancestor custom element:

// Let's assume we're using JSX for templating, but the elements being used as custom elements,
// and we're using a function-based custom element authoring library (f.e. solid-element, enhance, etc):
customElement('higher-up-element', function () {
  return <context-provider name="foo-context" value={anyValue}>
    <any-other-element />
  </context-provider>
})

Now here's the tree inside of any-other-element:

// Let's assume we're using JSX for templating, but the elements being used as custom elements.
// Also for sake of example, this is function-based element f.e. solid-element, enhance, etc
customElement('any-other-element', function () {
  const [fooContext, setFooContext] = createSignal(null)

  createEffect(() => {
    // re-runs any time the context changes because fooContext is reactive
    console.log('foo context', fooContext())
  })

  return <context-consumer name="foo-context" receive={value => setFooContext(value)}>
    <div>context value: {fooContext()}</div>
  </context-provider>
})

As we can see by the example,

  • the end user's ability to use context was not limited to class-based custom elements.
  • the pattern can even be used with custom elements in any other framework (React, Vue, Svelte, Solid, Angular, etc) whereas the class mixin format can't

React example:

export function MyComponent() {
  // ... use hooks here ...
  const [fooContext, setFooContext] = useState(null)

  return <context-consumer name="foo-context" receive={value => setFooContext(value)}>
    <div>context value: {fooContext}</div>
  </context-provider>
}

etc.

Some custom element libraries may ship with their own set of context to make composition and mixing and matching of their features flexible, and regardless if we're in React/Vue/Svelte/etc we'd want to be able to configure and use that custom element library.

For example, foo-context and any-other-element might both come from a library. A user would be able to configure the elements how they see fit:

// f.e. Preact code:
return <context-provider name="foo-context" value={fooValue}>
  <any-other-element />
  <any-other-element />
  <any-other-element />
</context-provider>

vs

// f.e. Preact code:
return (
  <context-provider name="foo-context" value={fooValue1}>
    <any-other-element />
  </context-provider>
  <context-provider name="foo-context" value={fooValue2}>
    <any-other-element />
  </context-provider>
  <context-provider name="foo-context" value={fooValue3}>
    <any-other-element />
  </context-provider>
)

A custom element library could also abstract it more, as needed, regardless of end user framework:

<!-- f.e. Vue code: -->
<template>
  <foo-context :value="fooValue1">
    <any-other-element />
  </foo-context>
  <foo-context :value="fooValue2">
    <any-other-element />
    <any-other-element />
  </foo-context>
</template>

<script setup>...</script>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions