<button id="add-hour">Add Hour</button>
	<button id="subtract-hour">Subtract Hour</button>
	<button id="date-style">Date Style</button>
	<button id="time-style">Time Style</button>
	<wc-local-date value="2020-11-06T01:00:00Z" date-style="short">2020-11-06T01:00:00Z</wc-local-date>
function asUTC(dateString){
    if (/\d\d\d\d-\d\d-\d\dT\d\d:\d\d$/.test(dateString)) {
        return `${dateString}:000Z`;
    }
    return dateString;
}

function hyphenCaseToCamelCase(text){
    return text.replace(/-([a-z])/g, g => g[1].toUpperCase());
}

class WcLocalDate extends HTMLElement {
    #value = new Date();
    #displayValue = "";
    #dateStyle = "full";
    #timeStyle = "full";
    static observedAttributes = ["value", "date-style", "time-style"];
    constructor() {
        super();
        this.bind(this);
    }
    bind(element){
        this.render = this.render.bind(element)
    }
    render(){
        this.shadow = this.attachShadow({ mode: "open" });
        this.shadow.innerHTML = `
            <div>${this.#displayValue}</div>
        `;
    }
    connectedCallback() {
        this.render();
        this.cacheDom();
    }
    cacheDom(){
        this.dom = {
            date: this.shadow.querySelector("div")
        };
    }
    attributeChangedCallback(name, oldValue, newValue) {
        if(name === "value"){
            this.value = new Date(asUTC(val));
        } else {
            this[hyphenCaseToCamelCase(name)] = newValue;
        } 
    }
    setDisplayValue(){
        const options = {};
        if (this.#dateStyle) {
            options.dateStyle = this.#dateStyle;
        }
        if (this.#timeStyle) {
            options.timeStyle = this.#timeStyle
        }
        const formatter = new Intl.DateTimeFormat(undefined, options);
        this.#displayValue = formatter.format(this.#value);
        if(this.dom?.date){
            this.dom.date.textContent = this.#displayValue;
        }
    }
    get value(){
        return this.#value;
    }
    set value(val){
        this.#value = val;
        this.setDisplayValue();
    }
    set dateStyle(val){
        this.#dateStyle = val;
        this.setDisplayValue();
    }
    set timeStyle(val){
        this.#timeStyle = val;
        this.setDisplayValue();
    }
}

customElements.define("wc-local-date", WcLocalDate);

//example page scripts
document.addEventListener("DOMContentLoaded", () => {
	const addHourBtn = document.querySelector("#add-hour");
	const subHourBtn = document.querySelector("#subtract-hour");
	const dateStyleBtn = document.querySelector("#date-style");
	const timeStyleBtn = document.querySelector("#time-style");
	const localDate = document.querySelector("wc-local-date");

	const hour = (1000 * 60 * 60);
	const format = ["full", "long", "medium", "short"];
	let date = new Date();
	let dateStyleIndex = 0;
	let timeStyleIndex = 0;
	

	addHourBtn.addEventListener("click", () => {
		date = new Date(date.getTime() + hour);
		localDate.value = date;
	});
	subHourBtn.addEventListener("click", () => {
		date = new Date(date.getTime() - hour);
		localDate.value = date;
	});
	dateStyleBtn.addEventListener("click", () => {
		dateStyleIndex = (dateStyleIndex + 1) % 4;
		localDate.dateStyle = format[dateStyleIndex];
	});
	timeStyleBtn.addEventListener("click", () => {
		timeStyleIndex = (timeStyleIndex + 1) % 4;
		localDate.timeStyle = format[timeStyleIndex];
	});
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.