
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).
| Option | Description and default |
|---|---|
speed | 100 milliseconds. Duration of the height transition; reduced-motion settings turn the transition off. |
collapsedHeight | 200 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. |
heightMargin | 16 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. |
embedCSS | true. 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. |
startOpen | false. Set true to initialize eligible blocks in the expanded state. |
sourceOrder | 'after'. Inserts the toggle 'before' or 'after' the content block. |
blockProcessed | Callback (element, collapsible). Runs once per target at initialization; collapsible is true when a toggle was added. |
beforeToggle | Callback (trigger, element, expanded) with the pre-toggle expansion state. Return false to cancel the action. |
afterToggle | Callback (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();| Method | Description |
|---|---|
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:
| Attribute | Purpose |
|---|---|
data-readmore | Marks a collapsible block. |
data-readmore-toggle | Marks the generated toggle and stores the controlled block’s ID. |
aria-controls | Identifies the block controlled by the toggle. |
aria-expanded | Reflects 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
- Line-Based Read More/Read Less in Vanilla JavaScript – ReadMore Lines
- Multiline Text Truncator In Vanilla JavaScript – Cuttr.js
- Read More / Read Less Functionality In Pure JavaScript – ReadMore.js
- Smooth Responsive Read More JavaScript Plugin – Readmore.js
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.







