This Web Components keeps the year in your copyright notice up-to-date.
export { CopyrightYearElement }
const name = "copyright-year";
class CopyrightYearElement extends HTMLSpanElement {
constructor() {
super();
}
connectedCallback() {
const year = new Date().getFullYear();
const shadow = this.attachShadow({ mode: "open" });
const span = document.createElement("span");
span.appendChild(document.createTextNode(`${this.textContent} - ${year}`));
shadow.appendChild(span);
}
}
customElements.define(name, CopyrightYearElement, {extends: 'span'});
Use the module.
<script type="module" src="copyright-year.js"></script>
Use the Web Component with the attribute is
<span>© <span is="copyright-year">2023</span> Web Component Super Hero</span>
or as a dedicated element.
<span>© <copyright-year>2023</copyright-year> Web Component Super Hero</span>
Thanks for sharing this @ceving!
@Danny-Engelman, I think you’re trying to help but your code review comes across as critical. Reviews can be tricky but try to give helpful pointers and justifications rather than opinions.
I see what you’re saying but there’s nothing wrong with exporting the class. It can be helpful to export components so they can be extended later on.
I would go for
export class CopyrightYearElement ...
for the sake of readability instead of hoisting the export to the top of the script, but this is fine.Fair enough. Your recommendation here is to extend
HTMLElement
instead ofHTMLSpanElement
, remove the{extends: 'span'}
option from the definition, and not to recommend using theis
attribute.Also fair enough. This is called inheritance – the constructor is inherited from the parent class,
HTMLElement
– and is a key part of object oriented programming or OOP.The code in the gist will not fail if you follow the instructions. You’re right that
connectedCallback
can be called before the component’s children are parsed, but the gist says to include the module with<script type="module">
which defers execution of the script until after the DOM is ready.I might be missing something but no revision of the gist seems to use
::slotted()
…?Hope that helps 🙂
I’d like to critique the code you shared too.
One tip to make things more readable is to tag the code block with the langugage you’re using, this enables syntax highlighting.edit: My bad, I was looking at one of the replies.I’m not sure where the
fixed
andguri="..."
attributes came from but they seem specific to your use-case and you may want to remove them.As mentioned,
<script>
is fine but you can run into ordering bugs if the script isn’t the last thing in your<body>
. You might want to consider using<script type="module">
or<script defer>
which is the current best practice and means you can include it in your<head>
with no problems.This is a neat utility function but it doesn’t feel like it should live in the constructor of this web component.
This also feels like it might be specific to your use-case. If it’s possible you might want to consider using CSS instead of non-breaking spaces.
I won’t review the CSS which seems custom, but it looks like a lot of this could be moved out of the shadow DOM which would save you from having to minify it manually. Bear in mind that code is read more times than it’s written, so if you’re able to write this out fully and minify it as part of a build step then future developers (or even yourself) will thank you.
I would recommend using
textContent
overinnerHTML
as a best practice where you can to avoid potential XSS injection attacks, although this case should be fine. I noticed you used
above and the unicode copywright character here, so it might be good to be consistent.Again this content feels specific to your use-case. If you add the
<a>
tag as a child in the HTML where this is used it would help keep the component generic.