diff --git a/packages/docs/components/molecules/Readmore/examples.md b/packages/docs/components/molecules/Readmore/examples.md
new file mode 100644
index 00000000..4a5e580c
--- /dev/null
+++ b/packages/docs/components/molecules/Readmore/examples.md
@@ -0,0 +1,26 @@
+---
+title: Readmore examples
+---
+
+# Examples
+
+## Simple Readmore
+
+
+
+:::details Code
+
+
+
+
+<<< ./components/molecules/Readmore/stories/simple/app.twig
+
+
+
+
+<<< ./components/molecules/Readmore/stories/app.js
+
+
+
+
+:::
diff --git a/packages/docs/components/molecules/Readmore/index.md b/packages/docs/components/molecules/Readmore/index.md
new file mode 100644
index 00000000..411b0606
--- /dev/null
+++ b/packages/docs/components/molecules/Readmore/index.md
@@ -0,0 +1,10 @@
+# Readmore
+
+
+
+## Table of content
+
+- [Examples](./examples)
diff --git a/packages/docs/components/molecules/Readmore/stories/app.js b/packages/docs/components/molecules/Readmore/stories/app.js
new file mode 100644
index 00000000..574dc408
--- /dev/null
+++ b/packages/docs/components/molecules/Readmore/stories/app.js
@@ -0,0 +1,13 @@
+import { Base, createApp } from '@studiometa/js-toolkit';
+import Readmore from '@studiometa/ui/molecules/Readmore/Readmore';
+
+class App extends Base {
+ static config = {
+ name: 'App',
+ components: {
+ Readmore,
+ },
+ };
+}
+
+export default createApp(App, document.body);
diff --git a/packages/docs/components/molecules/Readmore/stories/simple/app.twig b/packages/docs/components/molecules/Readmore/stories/simple/app.twig
new file mode 100644
index 00000000..455e152b
--- /dev/null
+++ b/packages/docs/components/molecules/Readmore/stories/simple/app.twig
@@ -0,0 +1,17 @@
+
+ {% embed '@ui/molecules/Readmore/Readmore.twig'
+ with {
+ mainContent: 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptatem expedita architecto maxime nostrum id voluptate perspiciatis sapiente explicabo earum culpa, sit fugit optio impedit iusto quos, illo, fugiat dolor sequi.',
+ hiddenContent: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Id expedita repellat debitis soluta praesentium magnam accusantium vero porro ullam, explicabo maiores harum incidunt fuga nisi? Accusamus odio voluptatum eos quas.',
+ data_options_btn_label_less: 'voir moins',
+ data_options_btn_label_more: 'voir plus'
+ }
+ %}
+ {% block button %}
+ {% include '@ui/atoms/Button/StyledButton.twig' with {
+ label: data_options_btn_label_more,
+ attr: { data_ref: 'btn' }
+ } %}
+ {% endblock %}
+ {% endembed %}
+
diff --git a/packages/docs/components/molecules/Readmore/stories/simple/story.md b/packages/docs/components/molecules/Readmore/stories/simple/story.md
new file mode 100644
index 00000000..5960edcd
--- /dev/null
+++ b/packages/docs/components/molecules/Readmore/stories/simple/story.md
@@ -0,0 +1,5 @@
+---
+layout: none
+---
+
+
diff --git a/packages/ui/molecules/Readmore/Readmore.ts b/packages/ui/molecules/Readmore/Readmore.ts
new file mode 100644
index 00000000..cb7b0667
--- /dev/null
+++ b/packages/ui/molecules/Readmore/Readmore.ts
@@ -0,0 +1,94 @@
+import { Base } from '@studiometa/js-toolkit';
+import type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';
+import { animate, easeInOutExpo } from '@studiometa/js-toolkit/utils';
+import type { Animate } from '@studiometa/js-toolkit/utils';
+/**
+ * Button Readmore class.
+ */
+export interface ReadmoreProps extends BaseProps {
+ $refs: {
+ btn: HTMLButtonElement;
+ btnLabel: HTMLElement;
+ mainContent: HTMLElement;
+ hiddenContent: HTMLElement;
+ };
+ $options: {
+ length: number;
+ animate: boolean;
+ btnLabelMore: string;
+ btnLabelLess: string;
+ };
+}
+
+/**
+ * Readmore Class
+ */
+export default class Readmore extends Base {
+ /**
+ * Config
+ */
+ static config: BaseConfig = {
+ name: 'Readmore',
+ refs: ['btn', 'btnLabel', 'mainContent', 'hiddenContent'],
+ options: {
+ length: Number,
+ animate: { type: Boolean, default: true },
+ btnLabelMore: { type: String, default: 'Voir plus' },
+ btnLabelLess: { type: String, default: 'Voir moins' },
+ },
+ };
+
+ animation: Animate;
+
+ /**
+ * On mounted
+ */
+ mounted() {
+ this.animation = animate(
+ this.$refs.hiddenContent,
+ [
+ { x: 0, scaleY: 0, opacity: 0 },
+ { x: 0, scaleY: 1, opacity: 1 },
+ ],
+ {
+ duration: 0.1,
+ easing: easeInOutExpo,
+ },
+ );
+ }
+
+ /**
+ * Show the content
+ */
+ show() {
+ setTimeout(() => {
+ this.$refs.hiddenContent.classList.remove('hidden');
+ }, 50);
+ this.animation.start();
+ this.$refs.btn.innerHTML = this.$options.btnLabelLess;
+ }
+
+ /**
+ * Hide the content
+ */
+ hide() {
+ this.$refs.hiddenContent.classList.add('hidden');
+ this.$refs.btn.innerHTML = this.$options.btnLabelMore;
+ }
+
+ /**
+ * Toggle the content visibility
+ */
+ toggle() {}
+
+ /**
+ * On button click
+ */
+ onBtnClick() {
+ if (this.$refs.hiddenContent.classList.contains('hidden')) {
+ this.show();
+ } else {
+ this.hide();
+ }
+ }
+}
diff --git a/packages/ui/molecules/Readmore/Readmore.twig b/packages/ui/molecules/Readmore/Readmore.twig
new file mode 100644
index 00000000..d222d865
--- /dev/null
+++ b/packages/ui/molecules/Readmore/Readmore.twig
@@ -0,0 +1,71 @@
+{#
+/**
+ * @file
+ * Readmore component.
+ *
+ * @param array $attr
+ * Use it to customize the root element attributes.
+ * @param string $mainContent
+ * Define the main content.
+ * @param array $main_content_attr
+ * Custom attributes for the main content.
+ * @param string $hiddenContent
+ * Define the hidden content.
+ * @param array $hidden_content_attr
+ * Custom attributes for the hidden content.
+ * @param array {label: string, label2: string} $btn
+* Define the button.
+ * @param array $btn_attr
+ * Custom attributes for the button.
+ * @param boolean $animation
+ * Wether to use an animation or not
+ * @param number $length
+ * The maximum characters length before hidding the content if only one content is provided.s
+ */
+#}
+
+{% set attributes =
+ merge_html_attributes(attr ?? null, { data_component: 'Readmore', data_option_animate: ' true' })
+%}
+
+{% set main_content_attributes =
+ merge_html_attributes(
+ main_content_attr ?? null,
+ { class: 'optionnel' },
+ { data_ref: 'mainContent', class: ['main_content'] }
+ )
+%}
+
+{% set hidden_content_attributes =
+ merge_html_attributes(
+ hidden_content_attr ?? null,
+ { class: 'optionnel' },
+ { data_ref: 'hiddenContent', aria_hidden: 'true', class: ['hidden_content hidden'] }
+ )
+%}
+
+{% set btn_attr =
+ merge_html_attributes(btn_attr ?? null, { class: 'optionnel' }, { class: ['button'] })
+%}
+
+{% set animation = animation|default(true) %}
+{% set length = length|default('70') %}
+
+
+ {% block mainContent %}
+
+ {{ mainContent }}
+
+ {% endblock %}
+ {% block hiddenContent %}
+
+ {{ hiddenContent }}
+
+ {% endblock %}
+ {% block button %}
+ {% include '@ui/atoms/Button/Button.twig' with {
+ label: data_options_btn_label_more,
+ attr: { data_ref: 'btn' }
+ } %}
+ {% endblock %}
+
diff --git a/packages/ui/molecules/Readmore/package.json b/packages/ui/molecules/Readmore/package.json
new file mode 100644
index 00000000..47369394
--- /dev/null
+++ b/packages/ui/molecules/Readmore/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "@studiometa/readmore",
+ "type": "module",
+ "version": "0.0.0"
+}