Logoreact-timeline-editor
Features

Custom Styles

Override default action block appearance with custom React renderers and CSS.

You can customize the appearance of action blocks using the getActionRender prop — returning any React node, styled however you want.

Live Preview

The preview shows two custom action types: an orange "Audio" block and a purple "Video" block, each rendered with custom JSX.

Custom Render via getActionRender

import React, { useState } from "react";
import {
  Timeline,
  TimelineRow,
  TimelineEffect,
} from "@keplar-404/react-timeline-editor";

const mockEffect: Record<string, TimelineEffect> = {
  effect0: { id: "effect0", name: "Audio Effect" },
  effect1: { id: "effect1", name: "Video Effect" },
};

const mockData: TimelineRow[] = [
  {
    id: "track-1",
    actions: [
      { id: "action-0", start: 0, end: 2, effectId: "effect0" },
      { id: "action-1", start: 3, end: 5, effectId: "effect1" },
    ],
  },
];

export const EditorCustomStyle = () => {
  const [data, setData] = useState(mockData);

  return (
    <div className="custom-editor-wrapper">
      <Timeline
        editorData={data}
        effects={mockEffect}
        onChange={setData}
        style={{ width: "100%", height: "100%" }}
        getActionRender={(action, row) => {
          if (action.effectId === "effect0") {
            return (
              <div className="custom-effect-audio">
                <span className="effect-text">🎵 {action.id}</span>
              </div>
            );
          } else if (action.effectId === "effect1") {
            return (
              <div className="custom-effect-video">
                <span className="effect-text">🎬 {action.id}</span>
              </div>
            );
          }
        }}
      />
    </div>
  );
};

The CSS

All block styling is done via standard CSS. Here are the classes used in the example above:

/* custom-timeline.css */

.custom-editor-wrapper {
  width: 100%;
  height: 400px;
}

/* Override the default action block height */
.custom-editor-wrapper .timeline-editor-action {
  height: 28px !important;
  top: 50%;
  transform: translateY(-50%);
}

/* Audio block */
.custom-effect-audio {
  width: 100%;
  height: 100%;
  background-color: #cd9541;
  border-radius: 4px;
  display: flex;
  align-items: center;
  color: white;
  font-size: 11px;
}

.custom-effect-audio .effect-text {
  margin-left: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Video block */
.custom-effect-video {
  width: 100%;
  height: 100%;
  background-color: #7846a7;
  border-radius: 4px;
  display: flex;
  align-items: center;
  color: white;
  font-size: 11px;
}

.custom-effect-video .effect-text {
  margin-left: 6px;
}

/* Override left/right resize handles */
.custom-editor-wrapper .timeline-editor-action-left-stretch::after,
.custom-editor-wrapper .timeline-editor-action-right-stretch::after {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  transform: rotate(45deg) scale(0.8);
  background: #aabbcc;
  border: none;
}

.custom-editor-wrapper .timeline-editor-action-left-stretch::after {
  left: -9px;
}

.custom-editor-wrapper .timeline-editor-action-right-stretch::after {
  right: -9px;
}

The built-in action wrapper automatically applies the class timeline-editor-action-effect-{effectId} to each block. You can use this to target blocks by effect in your CSS without needing getActionRender at all.

CSS Class Reference

ClassApplied to
.timeline-editorThe root timeline element
.timeline-editor-actionEach action block wrapper
.timeline-editor-action-effect-{effectId}Action wrapper with effect-specific class
.timeline-editor-action-left-stretchLeft resize handle
.timeline-editor-action-right-stretchRight resize handle

On this page