Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <main>

  <h1>Example word count element</h1>
  
  <p><word-count round="10"></word-count> words, <word-count minutes></word-count>-minute read.</p>
  
  <p>This is an example web component which counts the number of words in the page and can return reading time estimates.</p>
  
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pretium vel justo ac scelerisque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus vitae odio et eros malesuada hendrerit at in est. Proin sed est malesuada, consequat est in, pretium orci. Morbi nec elit laoreet, molestie massa a, finibus mi. Cras suscipit elit et cursus tincidunt.</p>
  
  <p>Nam tempus purus ac feugiat dictum. Integer quis risus et erat cursus ultrices sit amet vel erat. Nunc facilisis nisi purus, sit amet lacinia dolor feugiat quis. Maecenas eu massa sagittis, sagittis felis vel, viverra lacus. Sed id sollicitudin lacus, vel consequat ante. Aliquam in ornare est, in rhoncus turpis. Phasellus vulputate porta condimentum.</p>
  
  <p>Sed facilisis imperdiet massa, pharetra sollicitudin lacus feugiat vel. Donec aliquet molestie nisl, eu tincidunt ex faucibus ac. Vestibulum rutrum est ac augue lacinia rutrum. In aliquet purus a nisi faucibus, tincidunt vulputate lorem dapibus. Mauris nec leo arcu. Phasellus condimentum tortor ac eros maximus, nec pellentesque mi luctus. Praesent tempus aliquet nisi, in ullamcorper mi semper non. Morbi feugiat blandit nibh ut semper. Ut nec risus vulputate, sollicitudin augue eu, imperdiet nunc.</p>
  
  <button onclick="alert( document.querySelector('word-count').shadowRoot.textContent );">get count</button>
  
</main>
              
            
!

CSS

              
                body {
  font-family: sans-serif;
}

word-count {
  font-weight: bold;
}
              
            
!

JS

              
                /*
  <word-count> component
  returns the number of words in a page or the number of minutes to read it
  
  attributes:
  
    round="N"       - round words up to the nearest N
    minutes         - if set, show minutes to read rather than words
    wpm="N"         - reading words per minute (default 200)
    locale="lg-LG"  - set a number formatting locale (default is <html> lang)  

*/
class WordCount extends HTMLElement {

  // cached word count
  static words = 0;
  
  constructor() {

    // essential!
    super();
    
    // defaults
    this.locale = document.documentElement.getAttribute('lang') || 'en-US';
    this.round = 10;
    this.wpm = 200;
    this.minutes = false;
    
    // attach shadow root
    this.shadow = this.attachShadow({ mode: 'open' });

  }
  
  // component attributes
  static get observedAttributes() {
    return ['locale', 'round', 'minutes', 'wpm'];
  }
  
  // attribute change
  attributeChangedCallback(property, oldValue, newValue) {

    if (oldValue === newValue) return;
    this[property] = newValue || 1;
    
    // update existing
    if (WordCount.words) this.updateCount();
    
  }
  
  // connect component
  connectedCallback() {
    this.updateCount();
  }
  
  
  // disconnect component
  disconnectedCallback() {
  }
  
  // update count message
  updateCount() {
    
    if (!WordCount.words) {
      
      // get root <main> or </body>
      let element = document.getElementsByTagName('main');
      element = element.length ? element[0] : document.body;
      
      // do word count
      WordCount.words = element.textContent.trim().replace(/\s+/g, ' ').split(' ').length;
      
    }
    
    // locale
    const localeNum = new Intl.NumberFormat( this.locale );
   
    // output word or minute count
    this.shadow.textContent = localeNum.format( 
      this.minutes ? 
        Math.ceil( WordCount.words / this.wpm ) :
        Math.ceil( WordCount.words / this.round ) * this.round
    );
    
  }
  
}


// register component
window.customElements.define( 'word-count', WordCount );
              
            
!
999px

Console