Readmore.js: Read More / Read Less for Vanilla JS

Category: Javascript , Text | November 13, 2026
Authorjedfoster
Last UpdateNovember 13, 2026
LicenseMIT
Views0 views
Readmore.js: Read More / Read Less for Vanilla JS

Readmore.js is a vanilla JavaScript plugin that collapses long content blocks behind Read More and Close controls.

It supports responsive preview heights, custom toggle markup, and animated height transitions with no jQuery dependency.

The library is an upgrade to the original jQuery plugin. If you need the jQuery version, download it from our Readmore.js jQuery plugin article.

Features

  • Leaves short content blocks fully visible and omits unnecessary toggles.
  • Remeasures content when a block’s width changes.
  • Calls hooks during initialization and before or after toggling.
  • Disables height animations for reduced-motion preferences.
  • Supports programmatic toggling and instance cleanup.

How to Use It

Installation

Download and load the readmore.js script in the document.

<script src="/assets/readmore.js"></script>

Basic Usage

Add a content block and initialize Readmore.js after loading the script:

<article class="readmore-content" style="max-width: 36rem">
  <h3>Trail information</h3>
  <p>
    The route follows a wooded ridge before descending toward the river.
    Along the way, hikers pass two observation points, several creek
    crossings, and a short stretch of exposed rock. The western trail
    offers views of the valley near the final bend.
  </p>
  <p>
    The last section climbs to a lookout above the valley. Trail
    conditions change after rain, and the final crossing may require
    a short detour. Carry enough water for the return trip, check
    local access restrictions, and allow time for the steep descent.
  </p>
</article>
<script>
  new Readmore('.readmore-content', {
    collapsedHeight: 100,
    lessLink: '<a href="#">Read less</a>'
  });
</script>

ES Module Import

For native ES modules, save dist/readmore.es6.js as /assets/readmore.es6.js and use:

<script type="module">
  import Readmore from '/assets/readmore.es6.js';
  new Readmore('.readmore-content', {
    collapsedHeight: 100
  });
</script>

Responsive Preview Height

Set max-height in CSS to change the collapsed preview at a breakpoint.

.readmore-content {
  max-height: 6em;
}
@media (min-width: 640px) {
  .readmore-content {
    max-height: 12em;
  }
}

Custom Read More and Read Less Buttons

Use moreLink and lessLink to generate buttons when initializing the content block:

new Readmore('.readmore-content', {
  moreLink: '<button type="button">Show trail details</button>',
  lessLink: '<button type="button">Hide trail details</button>'
});

Configuration Options

Pass an options object as the second argument to new Readmore(target, options).

OptionDescription and default
speed100 milliseconds. Duration of the height transition; reduced-motion settings turn the transition off.
collapsedHeight200 pixels, or a function (element) => number. The function is evaluated at setup and on remeasurement; computed CSS max-height takes precedence over a numeric value.
heightMargin16 pixels. Adds a toggle only when the content height exceeds collapsedHeight + heightMargin.
moreLink'<a href="#">Read More</a>'. Accepts an HTML string or a function that receives the block and returns an HTML string.
lessLink'<a href="#">Close</a>'. Accepts an HTML string or a function that receives the block and returns an HTML string.
embedCSStrue. Injects base CSS for the block and toggle. Set false to provide those rules yourself.
blockCSS'display: block; width: 100%;'. CSS declarations inserted when embedCSS is enabled.
startOpenfalse. Set true to initialize eligible blocks in the expanded state.
sourceOrder'after'. Inserts the toggle 'before' or 'after' the content block.
blockProcessedCallback (element, collapsible). Runs once per target at initialization; collapsible is true when a toggle was added.
beforeToggleCallback (trigger, element, expanded) with the pre-toggle expansion state. Return false to cancel the action.
afterToggleCallback (trigger, element, expanded) with the post-toggle expansion state. Fires after the transition, or immediately at speed: 0 or reduced motion.

Scroll to the Start After Collapsing

Use afterToggle when closing a long block should return the reader to its beginning:

new Readmore('.readmore-content', {
  afterToggle(trigger, element, expanded) {
    if (!expanded) {
      element.scrollIntoView({ block: 'start' });
    }
  }
});

Constructor and Methods

The constructor and instance methods accept a CSS selector string, a DOM Element, or a NodeList. Keep the instance to control or remove managed blocks:

const readmore = new Readmore('.readmore-content', {
  collapsedHeight: 100
});
readmore.toggle('.readmore-content');
readmore.destroy();
MethodDescription
new Readmore(target, options?)Initializes selected content blocks. target accepts a CSS selector string, Element, or NodeList; options is optional.
readmore.toggle(target)Expands or collapses the selected managed blocks. target accepts a CSS selector string, Element, or NodeList.
readmore.destroy(target?)Removes the plugin’s controls, event listeners, and applied styles from selected managed blocks. Omit target to clean up the entire instance and restore the blocks’ original max-height.

HTML Attributes and Custom Styling

Readmore.js adds these attributes to collapsible blocks and their toggles:

AttributePurpose
data-readmoreMarks a collapsible block.
data-readmore-toggleMarks the generated toggle and stores the controlled block’s ID.
aria-controlsIdentifies the block controlled by the toggle.
aria-expandedReflects the expanded or collapsed state on the toggle element.

For custom block and toggle layouts, turn off the injected base rules and add your own CSS:

new Readmore('.readmore-content', {
  embedCSS: false
});
.readmore-content[data-readmore] {
  display: block;
  width: 100%;
}
[data-readmore-toggle] {
  display: inline-block;
  margin-top: 0.5rem;
  font-weight: 600;
  text-decoration: underline;
}

Alternatives and Related Resources

FAQs

Why does the Read More control not appear?

Readmore.js skips blocks whose measured height does not exceed collapsedHeight + heightMargin. Check the content height and the computed CSS max-height.

Can I initialize Readmore.js on dynamically added content?

Add the content to the document, then pass its element to new Readmore(element). Call destroy() on an old instance before removing or replacing its managed blocks.

Why is my custom height transition ignored?

Readmore.js applies the height transition inline. Use !important on your stylesheet’s transition declaration for [data-readmore] to override it.

You Might Be Interested In:


Leave a Reply