Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending and Overriding Styles in Polymer 2.0 #4683

Closed
dsanders11 opened this issue Jun 11, 2017 · 10 comments
Closed

Extending and Overriding Styles in Polymer 2.0 #4683

dsanders11 opened this issue Jun 11, 2017 · 10 comments

Comments

@dsanders11
Copy link

dsanders11 commented Jun 11, 2017

What is the proper way to extend an element and adjust styles, in Polymer 2.0? From the upgrade docs:

Make sure your element's styles are defined inside the template. Defining styles outside the template was deprecated in Polymer 1.x and is no longer supported.

So if you have to define styles inside of the template, it seems impossible to extend an element and override just the styles? Say I'm reusing an element FooElement and want to change some styles that aren't exposed as variables. I know, I'll subclass FooElement and make it look how I want for my own usage.

<dom-module id="foobar">
  <template>
    <style>
      p {
        color: red;
      }
    </style>
  </template>
  <script>
    class FoobarElement extends FooElement {
      static get is() { return 'foobar'; }
    }

    window.customElements.define(FoobarElement.is, FoobarElement);
  </script>
</dom-module>

This will result in...nothing being rendered for FoobarElement. By forcing style to be inside of the template, I end up nuking the DOM for the element when all I want to do is tweak the style.

I could hack it into ready() via something like:

ready() {
  super.ready();

  var newStyles = document.createElement('style');
  this.root.appendChild(newStyles);
  newStyles.innerHTML = `
    p { color: red; }
  `;
}

But isn't the point of Polymer to make this kind of stuff easier, not more hackish?

@web-padawan
Copy link
Contributor

Have a look at vaadin-themable-mixin for some inspiration.

@dfreedm
Copy link
Member

dfreedm commented Jun 17, 2017

I'm not sure that we have done the due diligence on exploring the right pattern here. @sorvell, we should make sure this pattern is easier to accomplish.

@dsanders11
Copy link
Author

@azakus, the way I've seen this kind of functionality allowed in other frameworks would have syntax something like:

<dom-module id="foobar">
  <template>
    <style>
      p {
        color: red;
      }
    </style>

    [[ template.super ]]
  </template>
  ...snip...
</dom-module>

Where [[ template.super ]] would insert the contents of the template of the element being extended. Although with CSS preference orders I guess if it just did a straight insert you'd have to put your style after the [[ template.super ]] to get the desired.

@kevinpschaaf
Copy link
Member

We haven't added declarative sugar for composing templates when subclassing in Polymer 2.0 (although we've done experiments with this in the past). That said, you have full control imperatively via the static get template getter.

Example:

<dom-module id="my-sub-element">
  <template id="styles">
    <style>
      p {
        color: red;
      }
    </style>
  </template>
  <script>
  let subTemplate;
  class MySubElement extends MySuperElement {
    static get template() {
      if (!subTemplate) {
        // start with clone of superclass template
        subTemplate = MySuperElement.template.cloneNode(true);
        // get some stuff you want to insert into super template
        const subStyle = Polymer.DomModule.import('my-sub-element', 'template#styles').content;
        // insert stuff in template before the super template's <style>
        // (or after, or wherever, you write the necessary code here)
        const superStyle = subTemplate.querySelector('style');
        superStyle.parentNode.insertBefore(subStyle, superStyle);
      }
      return subTemplate;
    }
  }
  customElements.define('my-sub-element', MySubElement);
  </script>
</dom-module>

Right now, this is the "right" way to do it (doing it this way means it's done statically once for the class, so you get all the efficiency of template cloning for the instances). Just because it's not "declarative" doesn't make it a hack; you have the full expressiveness of JavaScript here, and in the fullness of time we may encode the common expressiveness needed into a declarative template composition library if a de-facto one doesn't spring up in the community first.

@dsanders11
Copy link
Author

Just because it's not "declarative" doesn't make it a hack; you have the full expressiveness of JavaScript here

True, that doesn't make it a hack in it of itself. It's more that it feels like a common use case that has an obscure solution; one that isn't anywhere in the documentation, or even hinted at (AFAIK), and requires a decent understanding of how Polymer works.

Just my two cents as someone new to Polymer trying to do things which, to me, seem like intuitive usage of components. CSS just feels like an after thought when it comes to applying a consistent style across reusable components for your project.

@jaichandra
Copy link

Also, take a look at the template-mixin. I'm using this to extend paper-elements.

@clint77
Copy link

clint77 commented Nov 13, 2017

const superStyle = subTemplate.querySelector('style');

that is not working for me and just returning undefined

I tried this const superStyle = subTemplate.content.querySelector('style'); and works for me. Is it ok to use this instead? New to Polymer here.

@WooterTheTroubleshooter
Copy link

WooterTheTroubleshooter commented May 4, 2018

We haven't added declarative sugar for composing templates when subclassing in Polymer 2.0 (although we've done experiments with this in the past). That said, you have full control imperatively via the static get template getter.

I actually like the "experiments" behavior. Is the experiment still usable? Or is there any replacement that is known about at this time? A declarative method would be my preferred method of going about extending/inheriting templates.

Edit, to clarify my preference. I use polymer because it takes away writing how the template changes by manipulating strings from JavaScript. Having the template being the view and the JavaScript only the data to which the template is reactive to, makes using Polymer a very clean, easy to maintain, fast to produce experience.
Concatting strings and returning html from JavaScript obfuscates the clarity the provides.

<!-- super template -->
<template>
  <header></header>
  <template id="content">Hello World!</template>
  <footer></footer>
</template>
<!-- sub template -->
<template id="content">My Sub World!</template>

It would be very awesome to be able to declare templates to have the clean glue-less javascript Polymer also provides for binding data to the template.

@stale
Copy link

stale bot commented Mar 13, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Mar 13, 2020
@stale
Copy link

stale bot commented Apr 17, 2022

This issue has been automatically closed after being marked stale. If you're still facing this problem with the above solution, please comment and we'll reopen!

@stale stale bot closed this as completed Apr 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants