78 components ship across two packages. Props below are read out of the type definitions, so they match the installed version exactly.
@getnarro/core
<AnimatePresence>
AnimatePresence enables the animation of components that have been removed from the tree. When adding/removing more than a single child, every child must be given a unique key prop. Any motion components that have an exit property defined will animate out when removed from the tree. jsx import { motion, AnimatePresence } from 'framer-motion' export const Items = ({ items }) => ( <AnimatePresence> {items.map(item => ( <motion.div key={item.id} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} /> ))} </AnimatePresence> ) You can sequence exit animations throughout a tree using variants. If a child contains multiple motion components with exit props, it will only unmount the child once all motion components have finished animating out. Likewise, any components using usePresence all need to call safeToRemove.
import { AnimatePresence } from "@getnarro/core";
<Canvas>
A container for absolutely positioned elements
<Canvas>
<CanvasElement x={10} y={20} width={200} height={100}>
<div>Positioned content</div>
</CanvasElement>
<CanvasShape shape="circle" x={50} y={50} size={100} color="#3b82f6" />
</Canvas>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children elements to position |
background | string | β | Background color |
className | string | β | Additional CSS classes |
height | string | β | Height of the canvas (default: 100%) |
width | string | β | Width of the canvas (default: 100%) |
<CanvasElement>
A positioned element within a Canvas
<CanvasElement x={10} y={20} width={200} height={100}>
<div>Positioned at 10%, 20%</div>
</CanvasElement>
Using pixels:
```tsx
<CanvasElement x="100px" y="50px" width="200px" height="100px">
<div>Positioned at 100px, 50px</div>
</CanvasElement>
| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | yes | Children content |
| `x` | `PositionValue` | yes | X position (% or px) |
| `y` | `PositionValue` | yes | Y position (% or px) |
| `className` | `string` | β | Additional CSS classes |
| `height` | `PositionValue` | β | Height (% or px, optional) |
| `opacity` | `number` | β | Opacity (0-1) |
| `rotate` | `number` | β | Rotation in degrees |
| `width` | `PositionValue` | β | Width (% or px, optional) |
| `zIndex` | `number` | β | Z-index for layering |
### `<CanvasShape>`
A pre-built shape positioned on the Canvas
```tsx
<Canvas>
<CanvasShape shape="circle" x={50} y={50} size={100} color="#3b82f6" />
<CanvasShape shape="star" x={200} y={100} size={80} color="#fbbf24" />
<CanvasShape shape="arrow" x={300} y={50} size={120} color="#10b981" rotate={45} />
</Canvas>
| Prop | Type | Required | Description |
|---|---|---|---|
shape | ShapeType | yes | Shape type |
size | number | yes | Size of the shape |
x | PositionValue | yes | X position (% or px) |
y | PositionValue | yes | Y position (% or px) |
className | string | β | Additional CSS classes |
color | string | β | Fill color |
opacity | number | β | Opacity (0-1) |
rotate | number | β | Rotation in degrees |
stroke | string | β | Stroke color |
strokeWidth | number | β | Stroke width |
zIndex | number | β | Z-index for layering |
<ErrorBoundary>
Error Boundary component that catches errors and displays the overlay
<ErrorBoundary onError={(error) => console.error(error)}>
<Presentation>
<Slide>...</Slide>
</Presentation>
</ErrorBoundary>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children to render |
fallback | ReactNode | ((error: ErrorDetails, reset: () => void) => ReactNode) | β | Fallback component to render on error (optional, defaults to ErrorOverlay) |
onError | ((error: Error, errorInfo: ErrorInfo) => void) | β | Callback when an error occurs |
showOverlay | boolean | β | Enable development overlay (default: true in dev, false in prod) |
<ErrorOverlay>
Error overlay component for development
<ErrorOverlay
error={{
message: "Something went wrong",
stack: "Error: Something went wrong\n at Component ..."
}}
onDismiss={() => setError(null)}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
error | ErrorDetails | yes | Error details to display |
onDismiss | (() => void) | β | Callback to dismiss/reset the error |
showDismiss | boolean | β | Show dismiss button (default: true) |
<MarqueeRow>
One scrolling row of a marquee. Usually you want TrustedByMarquee, which arranges several of these.
| Prop | Type | Required | Description |
|---|---|---|---|
items | MarqueeItem[] | yes | Items to display in the marquee |
className | string | β | Additional CSS class for the container |
direction | "left" | "right" | β | Scroll direction |
gap | number | β | Gap between items in pixels (default: 16) |
isActive | boolean | β | Whether the animation is active |
itemMinWidth | number | β | Item minimum width in pixels (default: 180) |
renderItem | ((item: MarqueeItem, index: number) => ReactNode) | β | Custom item render function |
speed | number | β | Scroll speed (pixels per frame, default: 0.5) |
<MasonryBackground>
A full-bleed masonry grid of images that crossfades between them. Pauses while its slide is off screen, so an idle deck does no work.
<MasonryBackground
images={["/a.jpg", "/b.jpg", "/c.jpg"]}
gridColumns={12}
gridRows={6}
swapMinIntervalMs={3000}
swapMaxIntervalMs={6000}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
images | string[] | yes | Array of image URLs to display and cycle through |
backgroundColor | string | β | Background color (default: βblackβ) |
className | string | β | Additional CSS class for the container |
gridColumns | number | β | Number of grid columns (default: 12) |
gridRows | number | β | Number of grid rows (default: 6) |
imageBorderColor | string | β | Border color for images (default: βrgba(255, 255, 255, 0.6)β) |
imageBorderWidth | string | β | Border width for images (default: β1pxβ) |
imageGap | number | β | Gap between images in pixels (default: 6) |
initialFillTimeMs | number | β | Time in ms to fill the page with initial images (default: 800) |
isActive | boolean | β | Whether the animation is active |
swapMaxIntervalMs | number | β | Maximum time in ms between image swaps after initial fill (default: 2000) |
swapMinIntervalMs | number | β | Minimum time in ms between image swaps after initial fill (default: 1000) |
tileLayout | TileLayout[] | β | Grid tile layout configuration |
transitionDurationMs | number | β | Duration of crossfade transition in ms (default: 800) |
<Motion>
A Framer Motion animation wrapper Provides smooth, physics-based animations with 10+ built-in effects.
<Motion effect="slideUp" duration={0.5}>
<h1>Animated Title</h1>
</Motion>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children to animate |
className | string | β | Additional class names |
delay | number | β | Animation delay in seconds |
duration | number | β | Animation duration in seconds |
easing | MotionEasing | β | Easing function |
effect | MotionEffect | β | Animation effect to apply |
inView | boolean | β | Whether to trigger animation only when in view |
isActive | boolean | β | Whether animation has played (for controlled animations) |
onAnimationComplete | (() => void) | β | Callback when animation completes |
respectReducedMotion | boolean | β | Enable reduced motion fallback |
style | CSSProperties | β | Additional styles |
<MotionContainer>
Container for staggered child animations
<MotionContainer staggerDelay={0.1}>
<Motion effect="slideUp">Item 1</Motion>
<Motion effect="slideUp">Item 2</Motion>
<Motion effect="slideUp">Item 3</Motion>
</MotionContainer>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children to animate with stagger |
className | string | β | Additional class names |
isActive | boolean | β | Whether children should animate |
staggerDelay | number | β | Stagger delay between children in seconds |
style | CSSProperties | β | Additional styles |
<MotionList>
MotionList - Staggered list animation
| Prop | Type | Required | Description |
|---|---|---|---|
items | ReactNode[] | yes | List items |
className | string | β | Additional class names for container |
effect | MotionEffect | β | Animation effect for each item |
isActive | boolean | β | Whether animations are active |
itemClassName | string | β | Additional class names for items |
listStyle | "none" | "disc" | "decimal" | "check" | β | List style type |
staggerDelay | number | β | Stagger delay between items in seconds |
<MotionNumber>
Animated number counter
<MotionNumber value={1000000} prefix="$" separator duration={2} />
| Prop | Type | Required | Description |
|---|---|---|---|
value | number | yes | Target value |
className | string | β | Additional class names |
decimals | number | β | Number of decimal places |
delay | number | β | Delay before starting |
duration | number | β | Animation duration in seconds |
isActive | boolean | β | Whether animation is active |
prefix | string | β | Prefix (e.g., β$β) |
separator | boolean | β | Use thousands separator |
style | CSSProperties | β | Additional styles |
suffix | string | β | Suffix (e.g., β%β) |
<MotionPresence>
MotionPresence - Wrapper for AnimatePresence with slide-aware animations
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children to animate |
mode | "sync" | "wait" | "popLayout" | β | Animation mode |
presenceKey | string | β | Custom key for tracking |
<MotionSpotlight>
Apple Keynote-style Magic Move for images Creates smooth zoom and pan animations between slides. Uses Framer Motionβs layout animations for seamless morphing.
// Slide 1 - Overview
<MotionSpotlight
layoutId="product"
src="/product.jpg"
alt="Product"
x={50} y={50} scale={1}
width={800} height={400}
/>
// Slide 2 - Zoomed
<MotionSpotlight
layoutId="product"
src="/product.jpg"
alt="Product detail"
x={25} y={50} scale={2.5}
width={800} height={400}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | yes | Alt text for accessibility |
src | string | yes | Image source URL |
borderRadius | string | number | β | Border radius |
className | string | β | Additional class names |
duration | number | β | Animation duration in seconds |
height | string | number | β | Container height |
isActive | boolean | β | Whether currently active |
layoutId | string | β | Unique ID for cross-slide morphing |
onAnimationComplete | (() => void) | β | Callback when animation completes |
scale | number | β | Scale/zoom level |
shadow | boolean | β | Show shadow |
width | string | number | β | Container width |
x | number | β | X position as percentage (0-100) |
y | number | β | Y position as percentage (0-100) |
<MotionStep>
Individual step within MotionSteps container Shows when the current step is >= this stepβs number.
<MotionStep step={1} effect="scaleUp">
<div>This appears on step 1</div>
</MotionStep>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children to animate |
step | number | yes | Step number (0-indexed) - element shows when currentStep >= this value |
className | string | β | Additional class name |
duration | number | β | Animation duration in seconds |
easing | MotionEasing | β | Easing function |
effect | MotionEffect | β | Animation effect when revealed |
style | CSSProperties | β | Additional styles |
<MotionSteps>
Container for step-by-step animations triggered by keystrokes Wrap MotionStep children to create a sequence of animations. Press arrow keys (right/down) to advance, (left/up) to go back.
<MotionSteps totalSteps={3}>
<MotionStep step={0} effect="scaleUp">
<div>First element (visible immediately)</div>
</MotionStep>
<MotionStep step={1} effect="slideRight">
<div>Second element (press arrow key)</div>
</MotionStep>
<MotionStep step={2} effect="elastic">
<div>Third element (press again)</div>
</MotionStep>
</MotionSteps>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children - should be MotionStep components |
className | string | β | Additional class name |
loop | boolean | β | Whether to loop back to start after last step |
onComplete | (() => void) | β | Callback when all steps are complete |
startStep | number | β | Starting step (0-indexed) |
totalSteps | number | β | Total number of steps |
<MotionText>
Animated text with various effects
<MotionText type="typewriter" duration={0.05}>
Hello, World!
</MotionText>
| Prop | Type | Required | Description |
|---|---|---|---|
children | string | yes | Text content |
className | string | β | Additional class names |
delay | number | β | Delay before starting in seconds |
duration | number | β | Animation duration per unit in seconds |
isActive | boolean | β | Whether animation is active |
style | CSSProperties | β | Additional styles |
type | "blur" | "typewriter" | "wave" | "wordByWord" | "charByChar" | β | Animation type |
<MotionTransform>
Applies cumulative transforms to a single element across steps Use this inside MotionSteps to animate the SAME element through multiple transformation states (fade, zoom, move, rotate, etc.)
<MotionSteps totalSteps={4}>
<MotionTransform
transforms={[
{ opacity: 0 }, // Step 0 (hidden)
{ opacity: 1 }, // Step 1 (fade in)
{ opacity: 1, scale: 1.5 }, // Step 2 (zoom)
{ opacity: 1, scale: 1.5, x: 150 }, // Step 3 (move right)
]}
>
<div className="w-64 h-64 bg-blue-500">
Transform me!
</div>
</MotionTransform>
</MotionSteps>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children to transform |
transforms | TransformState[] | yes | Array of transform states for each step |
className | string | β | Additional class name |
duration | number | β | Animation duration in seconds |
easing | MotionEasing | β | Easing function |
style | CSSProperties | β | Additional styles |
<NebulaBackground>
An animated starfield with nebula glow, behind whatever you put in it.
<NebulaBackground isActive>
<Heading level={1}>Title over the stars</Heading>
</NebulaBackground>
| Prop | Type | Required | Description |
|---|---|---|---|
backgroundGradient | string | β | Background gradient (CSS value) |
children | ReactNode | β | Children to render on top of the background |
className | string | β | Additional CSS class for the container |
isActive | boolean | β | Whether the animation is active |
nebulaColors | NebulaGlow[] | β | Nebula glow effects configuration |
shootingStarDuration | number | β | Duration of shooting star animation in ms (default: 2000) |
shootingStarFrequency | number | β | Time between shooting stars in ms (default: 3000) |
starColors | StarColor[] | β | Star color distribution |
starLayers | StarLayer[] | β | Star layer configuration |
twinkleSpeed | { min: number; max: number; } | β | Twinkle speed range in ms |
<Notes>
Notes component - Speaker notes Notes are not rendered in the main presentation view. They are meant to be displayed in presenter mode or exported separately.
<Slide>
<h1>My Slide Title</h1>
<Notes>
Remember to explain the key points here.
- Point 1
- Point 2
</Notes>
</Slide>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Speaker notes content |
<OverviewGrid>
OverviewGrid component - Displays slides in a grid for quick navigation
| Prop | Type | Required | Description |
|---|---|---|---|
actions | NavigationActions | yes | Navigation actions |
slidesData | SlideData[] | yes | Slides data for rendering previews |
state | NavigationState | yes | Navigation state |
<Presentation>
Presentation component - Root container
<Presentation>
<Slide id="intro">
<h1>Welcome</h1>
</Slide>
<Slide id="content">
<h2>Main Content</h2>
</Slide>
</Presentation>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children slides |
aspectRatio | AspectRatio | β | Aspect ratio (default: β16:9β) |
autoPlay | number | boolean | number[] | β | Enable auto-play mode to automatically advance slides. Can be a boolean (uses default 5000ms interval) or a number specifying the interval in milliseconds. Can also be an array of numbers specifying the interval for each slide. |
autoPlayLoop | boolean | β | Whether to loop back to the first slide when auto-play reaches the end. Default: false |
baseHeight | number | β | Base height for viewport scaling (default: 1080). Content scales proportionally from this baseline |
baseWidth | number | β | Base width for viewport scaling (default: 1920). Content scales proportionally from this baseline |
className | string | β | Additional CSS classes |
embedded | boolean | β | Enable embedded mode for presentations in smaller containers. When true, viewport scaling uses container size instead of window size. Useful for embedding presentations in modals, cards, or side panels. |
enableViewportScaling | boolean | β | Enable viewport scaling (default: true). Scales content based on viewport size for responsive presentations |
favicon | string | null | β | Favicon URL or data URI for the presentation. Can be a path to an image file, a data URI, or undefined to use the default Narro favicon. Set to null to disable favicon management (keep existing favicon). |
initialSlide | number | β | Initial slide index |
keepAwake | boolean | β | Keep the screen awake while the presentation is open (Screen Wake Lock API, best-effort). Useful so the projector/laptop never sleeps mid-talk. Default: false |
keyboard | boolean | β | Enable keyboard navigation (default: true) |
maxDuration | number | β | Optional maximum duration in minutes for countdown timer in presenter panel |
mouse | boolean | β | Enable mouse navigation (default: true) |
onAutoPlayComplete | (() => void) | β | Callback when auto-play reaches the last slide and completes. Only called when autoPlay is enabled. |
onSlideChange | ((index: number) => void) | β | Callback when slide changes |
onSlidesData | ((slides: SlideData[]) => void) | β | Callback invoked with the registered slide data whenever the slide set changes. Useful for building companion views (notes, overviews) that need access to slide content and speaker notes. |
preserveAspectRatio | boolean | β | Preserve aspect ratio (default: true). When false, slides fill viewport |
routing | boolean | β | Enable URL-based routing (default: true) |
showAutoPlayIndicator | boolean | β | Show an auto-play indicator icon at the bottom right of the presentation. Shows a play/pause icon during playback and a replay icon when complete. Clicking the replay icon restarts the presentation. Default: false |
sync | PresentationSync | β | Broadcast the current slide to a presenter-sync relay so companion views (e.g. a speaker-notes window on a different port) can follow along live. Pass true to use the default relay URL, or an object to customise it. Default: false |
theme | PresentationTheme | β | Theme configuration for the presentation |
touch | boolean | β | Enable touch navigation (default: true) |
transform | TransformConfig | β | Transform-based animation configuration |
<PresenterNotes>
PresenterNotes component - live speaker-notes companion view.
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | The same slide elements rendered by the deck. Their inline <Notes> are harvested and shown in slide order. |
className | string | β | Additional CSS classes for the root container. |
currentSlide | number | β | Controlled current slide index. When provided, sync is ignored and the view follows this value (useful for tests or custom wiring). |
keepAwake | boolean | β | Keep the screen awake while the notes view is open (best-effort). Default: true (this is a presenter tool). |
pacing | PresenterPacing | β | Optional pacing schedule. When provided, the notes view shows an elapsed timer plus an on-time / ahead / over indicator and the planned total. |
script | ((slide: { id: string; index: number; step: number; }) => string | undefined) | β | Optional resolver for a fuller, per-slide script (e.g. a verbatim manuscript) shown in a secondary, scrollable pane next to the notes. Return undefined for slides that have no script. When omitted, no script pane is shown. |
sync | PresentationSync | β | Subscribe to a live deck via the presenter-sync relay. Pass true for the default relay URL or an object to customise it. |
<Slide>
Slide component - Individual slide wrapper
<Slide id="intro" layout="title">
<h1>Welcome to My Presentation</h1>
<p>Subtitle goes here</p>
</Slide>
With sub-slides
```tsx
<Slide id="multi-step" subSlides={[
{ id: "step1", content: <div>Step 1</div> },
{ id: "step2", content: <div>Step 2</div>, transition: "slide-left" }
]} />
| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `__slideIndex` | `number` | β | Internal: Explicit slide index from Presentation component |
| `background` | `string` | β | Background color or image |
| `children` | `ReactNode` | β | Children content |
| `className` | `string` | β | Additional CSS classes |
| `id` | `string` | β | Unique identifier for the slide |
| `layout` | `LayoutType` | β | Layout type (default: "default") |
| `subSlides` | `SubSlide[]` | β | Sub-slides for multi-step content within this slide |
| `transition` | `TransitionEffect` | β | Transition effect |
### `<SlideContent>`
SlideContent component - Content layout container
```tsx
<Slide>
<SlideContent layout="centered">
<h1>Centered Content</h1>
</SlideContent>
</Slide>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Children content |
className | string | β | Additional CSS classes |
layout | "default" | "centered" | "top" | "bottom" | β | Layout mode |
<TransformSlide>
A slide with multiple sub-slides and transform-based navigation
| Prop | Type | Required | Description |
|---|---|---|---|
subSlides | TransformSubSlide[] | yes | Array of sub-slides with their positions |
background | string | β | Background color or gradient |
className | string | β | Additional CSS classes |
duration | number | β | Transition duration in seconds (default: 1) |
easing | "linear" | "easeIn" | "easeOut" | "easeInOut" | "circInOut" | "backInOut" | β | Transition easing (default: βeaseInOutβ) |
initialSubSlide | number | β | Initial sub-slide index (default: 0) |
perspective | boolean | β | Enable 3D perspective (default: true) |
perspectiveValue | number | β | Perspective value in pixels (default: 1000) |
<TrustedByMarquee>
Rows of logos or names scrolling infinitely in alternating directions.
<TrustedByMarquee
rows={[[{ name: "Acme", color: "#ffffff" }], [{ name: "Globex", color: "#60a5fa" }]]}
isActive
baseSpeed={40}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
rows | MarqueeItem[][] | yes | Array of row data, each containing items |
baseSpeed | number | β | Base scroll speed (default: 0.3) |
className | string | β | Additional CSS class for the container |
gap | number | β | Gap between items in pixels (default: 16) |
isActive | boolean | β | Whether the animation is active |
itemMinWidth | number | β | Item minimum width in pixels (default: 180) |
renderItem | ((item: MarqueeItem, index: number) => ReactNode) | β | Custom item render function |
rowGap | number | β | Gap between rows (default: 8) |
speedIncrement | number | β | Speed increment per row (default: 0.05) |
@getnarro/shared-ui
<AgendaItem>
A styled agenda item component Displays an agenda item with a centered number in bold with a colored underline, followed by descriptive text. Useful for agenda presentations and step-by-step processes.
<AgendaItem number={1} title="Introduction" />
<AgendaItem number={2} title="Main Topic" underlineColor="#00BFA5" />
| Prop | Type | Required | Description |
|---|---|---|---|
number | number | yes | The number of the agenda item |
title | string | yes | Title of the agenda item |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
underlineColor | string | β | Color of the underline |
<AnimatedList>
List with staggered animations Note: Import the animations CSS file to use this component: import β@getnarro/shared-ui/styles/animations.cssβ;
<AnimatedList
items={['First point', 'Second point', 'Third point']}
animation="slide-up"
staggerDelay={150}
variant="check"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
items | ReactNode[] | yes | List items to animate |
animation | ListAnimationType | β | Animation type |
className | string | β | Additional CSS classes |
duration | number | β | Animation duration per item in milliseconds |
initialDelay | number | β | Delay before starting first animation in milliseconds |
isActive | boolean | β | Override slide active state |
ordered | boolean | β | Ordered or unordered list |
staggerDelay | number | β | Delay between each item in milliseconds |
variant | "disc" | "decimal" | "check" | "arrow" | "none" | β | List style variant |
<Animation>
A CSS animation wrapper component When used inside a Slide component from narro, animations will only trigger when the slide becomes active. Note: Import the animations CSS file to use this component: import β@getnarro/shared-ui/styles/animations.cssβ;
<Animation type="slide-up" delay={200} duration={500}>
<Heading level={1}>Animated Title</Heading>
</Animation>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
delay | number | β | Animation delay (ms) |
duration | number | β | Animation duration (ms) |
easing | "linear" | "ease-out" | "ease-in-out" | "ease" | "ease-in" | β | Animation easing |
isActive | boolean | β | Override slide active state (for use without narro context) |
trigger | "mount" | "hover" | "visible" | β | Trigger animation on mount |
type | AnimationType | β | Animation type |
<BigText>
Extremely large, impactful text component
<BigText effect="gradient" animate="blur-reveal">
IMPACT
</BigText>
| Prop | Type | Required | Description |
|---|---|---|---|
align | "center" | "left" | "right" | β | Text alignment |
animate | BigTextAnimation | β | Animation preset |
animationDuration | number | β | Animation duration in milliseconds |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
color | string | β | Text color |
effect | BigTextEffect | β | Text effect to apply |
gradientColors | string | β | Custom gradient colors (when effect is βgradientβ) |
<Chart>
A simple chart component This is a basic CSS-based implementation suitable for presentations. For more advanced charts, consider integrating with Chart.js or Recharts.
<Chart
type="bar"
data={[
{ label: 'Q1', value: 100 },
{ label: 'Q2', value: 150 },
{ label: 'Q3', value: 200 },
]}
title="Quarterly Sales"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
data | ChartDataPoint[] | yes | Chart data |
type | "line" | "bar" | "pie" | "donut" | yes | Chart type |
className | string | β | Additional CSS classes |
colors | string[] | β | Color palette |
height | number | β | Chart height |
showLegend | boolean | β | Show legend |
title | string | β | Chart title |
<Code>
A code block component with optional line numbers and copy button Note: This is a basic implementation. For production use, consider integrating with Shiki or Prism for proper syntax highlighting.
<Code language="typescript" lineNumbers>
{`const greeting = "Hello, World!";
console.log(greeting);`}
</Code>
| Prop | Type | Required | Description |
|---|---|---|---|
children | string | yes | Code content |
className | string | β | Additional CSS classes |
copyButton | boolean | β | Show copy button |
highlightLines | string | β | Lines to highlight (comma-separated or range) |
language | string | β | Programming language |
lineNumbers | boolean | β | Show line numbers |
theme | "dark" | "light" | β | Theme variant |
<CommentForm>
A form for creating or editing comments
<CommentForm
slideId="slide-1"
defaultAuthor="John Doe"
onSubmit={(comment) => handleAddComment(comment)}
onCancel={() => setShowForm(false)}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
onSubmit | (comment: Omit<SlideComment, "id" | "createdAt">) => void | yes | Callback when comment is submitted |
slideId | string | yes | Slide ID to add comment to |
className | string | β | Additional CSS classes |
defaultAuthor | string | β | Default author name |
initialContent | string | β | Initial content (for editing) |
isEditing | boolean | β | Whether this is editing an existing comment |
onCancel | (() => void) | β | Callback when form is cancelled |
parentId | string | β | Parent comment ID for replies |
placeholder | string | β | Placeholder text |
position | CommentPosition | β | Position for inline comments |
<CommentItem>
Displays a single comment with actions
<CommentItem
comment={comment}
onEdit={(id) => handleEdit(id)}
onDelete={(id) => handleDelete(id)}
onResolve={(id, resolved) => handleResolve(id, resolved)}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
comment | SlideComment | yes | The comment to display |
className | string | β | Additional CSS classes |
currentUser | string | β | Current userβs name (to determine if they can edit/delete) |
onDelete | ((commentId: string) => void) | β | Callback when delete is clicked |
onEdit | ((commentId: string) => void) | β | Callback when edit is clicked |
onReaction | ((commentId: string, emoji: string) => void) | β | Callback when a reaction is added |
onReply | ((commentId: string, content: string) => void) | β | Callback when reply is submitted |
onResolve | ((commentId: string, resolved: boolean) => void) | β | Callback when resolve is toggled |
replies | SlideComment[] | β | Child comments (replies) |
showReplyForm | boolean | β | Whether to show the reply form |
<CommentMarker>
A visual indicator for comment positions on slides
<CommentMarker
position={{ x: 50, y: 30 }}
count={3}
onClick={() => setShowComments(true)}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
position | CommentPosition | yes | Position of the marker on the slide (percentage 0-100) |
className | string | β | Additional CSS classes |
commentId | string | β | Comment ID this marker represents |
count | number | β | Number of comments at this position |
isActive | boolean | β | Whether the marker is in an active/selected state |
onClick | (() => void) | β | Callback when marker is clicked |
<CommentPanel>
A sidebar panel for managing comments
<CommentPanel
slideId="slide-1"
comments={allComments}
onAddComment={(comment) => addComment(comment)}
onDeleteComment={(id) => deleteComment(id)}
currentUser="John Doe"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
comments | SlideComment[] | yes | All comments data |
onAddComment | (comment: Omit<SlideComment, "id" | "createdAt">) => void | yes | Callback to add a new comment |
className | string | β | Additional CSS classes |
currentUser | string | β | Current user name |
filter | CommentFilterOptions | β | Filter options |
isCollapsed | boolean | β | Whether the panel is in collapsed state |
onCollapseChange | ((collapsed: boolean) => void) | β | Callback when collapse state changes |
onDeleteComment | ((commentId: string) => void) | β | Callback to delete a comment |
onFilterChange | ((filter: CommentFilterOptions) => void) | β | Callback when filter changes |
onResolveComment | ((commentId: string, resolved: boolean) => void) | β | Callback to resolve/unresolve a comment |
onUpdateComment | ((commentId: string, updates: Partial<SlideComment>) => void) | β | Callback to update a comment |
slideId | string | β | Slide ID to show comments for (if undefined, shows all) |
<ContentSlide>
A slide with optional title and content area
<ContentSlide title="Key Features">
<List items={['Feature 1', 'Feature 2', 'Feature 3']} />
</ContentSlide>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
title | ReactNode | β | Slide title |
<CountingNumber>
Animated number counter
<CountingNumber
value={1000000}
duration={2000}
format={{ prefix: "$", separator: true }}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
value | number | yes | Target value to count to |
className | string | β | Additional CSS classes |
delay | number | β | Delay before starting animation in milliseconds |
duration | number | β | Animation duration in milliseconds |
easing | "linear" | "ease-out" | "ease-in-out" | β | Animation easing |
format | { decimals?: number | undefined; prefix?: string | undefined; suffix?: string | undefined; separator?: boolean | undefined; locale?: string | undefined; } | β | Number format options |
from | number | β | Starting value (default: 0) |
isActive | boolean | β | Override slide active state |
onComplete | (() => void) | β | Callback when animation completes |
<Diagram>
A diagram rendering component This is a basic text/pre-formatted implementation. For actual Mermaid support, integrate with the mermaid library: https://mermaid.js.org/
// Text/ASCII diagram
<Diagram type="text">
{`
+--------+ +--------+
| Client | --> | Server |
+--------+ +--------+
`}
</Diagram>
// Mermaid (requires mermaid library integration)
<Diagram type="mermaid">
{`graph LR
A[Client] --> B[Server]
B --> C[Database]`}
</Diagram>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
theme | "dark" | "light" | "forest" | β | Diagram theme |
type | "text" | "mermaid" | β | Diagram type |
<DottedArc>
Decorative concentric dotted arcs Creates a series of concentric arcs with dashed lines in varying colors. Used as a decorative element for title slides and maintaining brand consistency.
<DottedArc
colors={["#ff6b35", "#4ecdc4", "#1a535c"]}
position="bottom-right"
/>
// Custom sizing and spacing
<DottedArc
colors={["orange", "green", "blue"]}
width={3}
spacing={10}
size={400}
position="bottom-left"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
colors | string[] | yes | Array of colors for each arc |
className | string | β | Additional CSS classes |
position | "bottom-right" | "bottom-left" | "top-right" | "top-left" | β | Arc position |
size | number | β | Size of the arc container |
spacing | number | β | Spacing between arcs |
width | number | β | Line width for arcs |
<DualColumnTextAndImage>
A two-column layout where text is on one side and an image is on the other
<DualColumnTextAndImage
text="This is the text content"
image="/path/to/image.png"
imageAlt="Description of image"
gap="md"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
image | string | yes | URL of the image to display in the right column |
text | ReactNode | yes | Text content to display in the left column |
className | string | β | Additional CSS classes |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between columns |
imageAlt | string | β | Alt text for the image |
reverse | boolean | β | Reverse the layout (image left, text right) |
<Embed>
External content embedding component Supports YouTube, Vimeo, Google Slides, websites, web applications, and generic iframes.
// Embed a YouTube video
<Embed
url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
title="Video demonstration"
aspectRatio="16:9"
/>
// Embed a web application with sandbox restrictions
<Embed
url="https://codesandbox.io/embed/..."
title="Live code demo"
sandbox="allow-scripts allow-same-origin"
loading="lazy"
/>
// Embed a website
<Embed
url="https://example.com"
title="Example website"
aspectRatio="16:9"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
url | string | yes | URL to embed (YouTube, Vimeo, websites, web apps, etc.) |
allow | string | β | Custom permissions for iframe (default includes common permissions) |
allowFullscreen | boolean | β | Allow fullscreen |
aspectRatio | "1:1" | "16:9" | "4:3" | β | Aspect ratio |
className | string | β | Additional CSS classes |
loading | "lazy" | "eager" | β | Lazy loading strategy |
referrerPolicy | "no-referrer" | "no-referrer-when-downgrade" | "origin" | "origin-when-cross-origin" | "same-origin" | "strict-origin" | "strict-origin-when-cross-origin" | "unsafe-url" | β | Referrer policy |
sandbox | string | β | Sandbox restrictions for iframe security |
title | string | β | Embed title for accessibility |
<FlowDiagram>
A visual representation of a process flow with steps
<FlowDiagram
steps={[
{label: 'Step 1', icon: '/icon1.png', description: 'First step'},
{label: 'Step 2', icon: '/icon2.png', description: 'Second step'}
]}
direction="horizontal"
color="#08979c"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
steps | FlowStep[] | yes | List of steps with labels and optional icons |
className | string | β | Additional CSS classes |
color | string | β | Color for step boxes and connectors |
direction | "horizontal" | "vertical" | β | Direction of flow |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between steps |
<FourColumn>
A four-column layout component with equal columns
<FourColumn
first={<Text>Column 1</Text>}
second={<Text>Column 2</Text>}
third={<Text>Column 3</Text>}
fourth={<Text>Column 4</Text>}
gap="lg"
align="center"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
first | ReactNode | yes | First column content |
fourth | ReactNode | yes | Fourth column content |
second | ReactNode | yes | Second column content |
third | ReactNode | yes | Third column content |
align | "center" | "start" | "end" | "stretch" | β | Vertical alignment |
className | string | β | Additional CSS classes |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between columns |
responsive | boolean | β | Stack columns on small screens |
<Fragment>
Step-by-step reveal component Each Fragment animates in sequence based on its order prop. The delay is calculated as: order * staggerDelay When used inside a Slide component from narro, animations will only trigger when the slide becomes active. Note: Import the animations CSS file to use this component: import β@getnarro/shared-ui/styles/animations.cssβ;
<Fragment order={1} effect="fade-in">
<Text>This appears first (after 400ms)</Text>
</Fragment>
<Fragment order={2} effect="slide-up">
<Text>This appears second (after 800ms)</Text>
</Fragment>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
duration | number | β | Animation duration (ms) |
effect | FragmentEffect | β | Animation effect |
isActive | boolean | β | Override slide active state (for use without narro context) |
order | number | β | Order in which fragment appears |
staggerDelay | number | β | Delay between each fragment (ms) - used to stagger animations |
<Grid>
A flexible grid layout component
<Grid columns={3} gap="md">
<Card>Item 1</Card>
<Card>Item 2</Card>
<Card>Item 3</Card>
</Grid>
| Prop | Type | Required | Description |
|---|---|---|---|
align | "center" | "start" | "end" | "stretch" | β | Horizontal alignment |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
columns | 2 | 3 | 4 | 5 | 6 | 1 | β | Number of columns |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between items |
justify | "center" | "start" | "end" | "stretch" | β | Vertical alignment |
<Heading>
A styled heading component (h1-h6)
<Heading level={1}>Main Title</Heading>
<Heading level={2} color="primary">Subtitle</Heading>
| Prop | Type | Required | Description |
|---|---|---|---|
align | "center" | "left" | "right" | β | Text alignment |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
color | "default" | "primary" | "muted" | "accent" | β | Color variant |
level | 2 | 3 | 4 | 5 | 6 | 1 | β | Heading level (1-6) |
<HexPatternBackground>
A background with a hexagonal pattern
<HexPatternBackground backgroundColor="#00d9c4" hexColor="#08979c">
<h1>Content here</h1>
</HexPatternBackground>
| Prop | Type | Required | Description |
|---|---|---|---|
backgroundColor | string | β | Background color (hex or rgb) |
children | ReactNode | β | Content to be rendered on top of the hexagon pattern background |
className | string | β | Additional CSS classes |
hexColor | string | β | Hexagon stroke color (hex or rgb) |
patternSize | "sm" | "md" | "lg" | β | Pattern size (affects hexagon scale) |
<Icon>
A simple icon component This is a basic implementation using Unicode symbols and emoji. For production use with custom icons, consider integrating with a proper icon library like Lucide, Heroicons, or Font Awesome.
<Icon name="check" size="lg" color="green" />
<Icon name="github" size={32} />
| Prop | Type | Required | Description |
|---|---|---|---|
name | string | yes | Icon name or SVG content |
className | string | β | Additional CSS classes |
color | string | β | Icon color |
label | string | β | Accessibility label |
size | number | "sm" | "md" | "lg" | "xl" | β | Icon size |
<Image>
An optimized image component with filter support
<Image
src="/images/photo.jpg"
alt="A beautiful landscape"
fit="cover"
rounded="lg"
shadow
filter="grayscale"
/>
Custom filter:
```tsx
<Image
src="/images/photo.jpg"
alt="Custom filtered"
customFilter="brightness(80%) contrast(110%)"
/>
```tsx
Color overlay:
```tsx
<Image
src="/images/photo.jpg"
alt="Blue tinted"
overlay="#3b82f6"
overlayOpacity={0.4}
/>
| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `alt` | `string` | yes | Alt text for accessibility |
| `src` | `string` | yes | Image source URL |
| `children` | `ReactNode` | β | Children content |
| `className` | `string` | β | Additional CSS classes |
| `customFilter` | `string` | β | Custom CSS filter value (overrides filter preset) |
| `filter` | `ImageFilter` | β | Apply CSS filter preset |
| `fit` | `"none" \| "cover" \| "contain" \| "fill"` | β | Object fit mode |
| `height` | `string \| number` | β | Height constraint |
| `overlay` | `string` | β | Color overlay (CSS color value) |
| `overlayOpacity` | `number` | β | Opacity of the color overlay (0-1, default: 0.5) |
| `rounded` | `"none" \| "sm" \| "md" \| "lg" \| "full"` | β | Border radius |
| `shadow` | `boolean` | β | Add shadow |
| `width` | `string \| number` | β | Width constraint |
### `<ImageBackground>`
A full-bleed background image with content overlay
```tsx
<ImageBackground
src="/images/hero.jpg"
alt="Hero background"
overlay="dark"
kenBurns
>
<Heading level={1}>Bold Title</Heading>
<Text>Subtitle text here</Text>
</ImageBackground>
| Prop | Type | Required | Description |
|---|---|---|---|
src | string | yes | Image source URL |
alt | string | β | Image alt text for accessibility |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
kenBurns | boolean | β | Enable Ken Burns animation effect (slow zoom/pan) |
kenBurnsDuration | number | β | Ken Burns animation duration in seconds |
overlay | ImageBackgroundOverlay | β | Overlay type for text readability |
overlayColor | string | β | Custom overlay color (CSS color value) |
position | "center" | "cover" | "contain" | "top" | "bottom" | β | Image positioning |
<ImageSlide>
A full-bleed image slide with optional overlay
<ImageSlide
src="/images/hero.jpg"
alt="Hero image"
overlay={<Heading level={1}>Welcome</Heading>}
overlayPosition="center"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
src | string | yes | Image source URL |
alt | string | β | Image alt text |
className | string | β | Additional CSS classes |
fit | "cover" | "contain" | "fill" | β | Object fit mode |
overlay | ReactNode | β | Overlay content |
overlayPosition | "center" | "top" | "bottom" | β | Overlay position |
<ImageSpotlight>
Keynote-style Magic Move for images Creates smooth zoom and pan animations between slides. Elements with the same spotlightId will animate smoothly when transitioning between slides.
// Slide 1 - Overview (centered, no zoom)
<ImageSpotlight
spotlightId="diagram"
src="/architecture.svg"
alt="Architecture diagram"
x={50}
y={50}
scale={1}
width="100%"
height={400}
/>
// Slide 2 - Zoom to top-left element
<ImageSpotlight
spotlightId="diagram"
src="/architecture.svg"
alt="Architecture diagram"
x={25}
y={25}
scale={2.5}
width="100%"
height={400}
/>
// Slide 3 - Pan to bottom-right element
<ImageSpotlight
spotlightId="diagram"
src="/architecture.svg"
alt="Architecture diagram"
x={75}
y={75}
scale={2.5}
width="100%"
height={400}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | yes | Alt text for accessibility |
spotlightId | string | yes | Unique identifier for cross-slide morphing - elements with same id will animate between slides |
src | string | yes | Image source URL |
className | string | β | Additional CSS classes for container |
duration | number | β | Animation duration in ms, default 800 |
easing | "linear" | "ease-out" | "ease-in-out" | "ease" | "ease-in" | "spring" | β | Animation easing function |
height | string | number | β | Container height (CSS value or number in px) |
imageClassName | string | β | Additional CSS classes for image |
onAnimationComplete | (() => void) | β | Callback when animation completes |
overlay | ReactNode | β | Optional overlay content that appears on top |
rounded | "none" | "sm" | "md" | "lg" | "xl" | "full" | β | Border radius |
scale | number | β | Scale/zoom level, default 1 |
shadow | boolean | β | Show shadow |
width | string | number | β | Container width (CSS value or number in px) |
x | number | β | X position as percentage (0-100), default 50 (centered) |
y | number | β | Y position as percentage (0-100), default 50 (centered) |
<InfoCardWithIcon>
A styled information card with icon Displays an icon on the left with bold headings and descriptive text to the right. Uses consistent alignment and spacing. Perfect for concept highlights and important points.
<InfoCardWithIcon
iconSrc="/icon.svg"
title="Key Feature"
description="This is an important concept to highlight"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
description | string | yes | Description text explaining the icon |
iconSrc | string | yes | URL for the icon image |
title | string | yes | Title of the info card |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
<List>
An animated list component
<List
items={['First point', 'Second point', 'Third point']}
variant="check"
animated
/>
| Prop | Type | Required | Description |
|---|---|---|---|
items | ReactNode[] | yes | List items |
animated | boolean | β | Enable animations |
animationDelay | number | β | Animation delay between items (ms) |
className | string | β | Additional CSS classes |
ordered | boolean | β | Ordered or unordered list |
variant | "disc" | "decimal" | "check" | "arrow" | "none" | β | List style |
<LogoGrid>
A grid layout for displaying multiple logos with even spacing
<LogoGrid
logos={[
{src: '/path/to/logo1.png', name: 'Company 1'},
{src: '/path/to/logo2.png', name: 'Company 2'}
]}
columns={3}
gap="md"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
logos | Logo[] | yes | Array of logo objects with source and alt text. |
className | string | β | Additional CSS classes |
columns | 2 | 3 | 4 | 5 | 6 | β | Number of columns |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between logos |
<MorphElement>
Element that morphs across slides using View Transitions API When elements with the same transitionName exist on consecutive slides, they will smoothly morph into each other during slide transitions.
// Slide 1
<MorphElement transitionName="hero-image">
<img src="product.jpg" style={{ width: 200 }} />
</MorphElement>
// Slide 2 - same transitionName, different size
<MorphElement transitionName="hero-image">
<img src="product.jpg" style={{ width: "100%" }} />
</MorphElement>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Element content |
transitionName | string | yes | Unique name for cross-slide morphing |
as | ElementType<any, keyof IntrinsicElements> | β | HTML tag to render |
className | string | β | Additional CSS classes |
style | CSSProperties | β | Additional inline styles |
<ProcessFlowChart>
Interactive flowchart for process visualization Creates a flowchart with customizable nodes and connections. Nodes are automatically laid out based on the direction prop, and connections are drawn between them with arrows.
<ProcessFlowChart
nodes={[
{ id: "start", label: "Start", color: "#4ecdc4" },
{ id: "process", label: "Process", color: "#ff6b35" },
{ id: "end", label: "End", color: "#95e1d3" }
]}
connections={[
{ from: "start", to: "process" },
{ from: "process", to: "end" }
]}
direction="horizontal"
/>
// Vertical flow with custom styling
<ProcessFlowChart
nodes={[
{ id: "1", label: "Input", color: "#1a535c", textColor: "#fff" },
{ id: "2", label: "Transform", color: "#4ecdc4" },
{ id: "3", label: "Output", color: "#ff6b35", textColor: "#fff" }
]}
connections={[
{ from: "1", to: "2", label: "data" },
{ from: "2", to: "3", label: "result" }
]}
direction="vertical"
nodeGap="lg"
arrowStyle="dashed"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
connections | ProcessFlowConnection[] | yes | Array of connections between node ids |
nodes | ProcessFlowNode[] | yes | Array of nodes with labels and colors |
arrowStyle | "solid" | "dashed" | β | Arrow style for connections |
className | string | β | Additional CSS classes |
direction | "horizontal" | "vertical" | β | Orientation of the flow |
nodeGap | "sm" | "md" | "lg" | β | Gap between nodes |
<ProfileCard>
A styled profile card component Displays a profile image, name, title, and associated company icons. Perfect for team introductions and speaker introductions.
<ProfileCard
imageSrc="/avatar.jpg"
name="John Doe"
title="CEO & Founder"
companyIcons={["/company1.svg", "/company2.svg"]}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
imageSrc | string | yes | Source URL for the profile image |
name | string | yes | Name of the individual |
title | string | yes | Title or role of the individual |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
companyIcons | string[] | β | Array of icon URLs to display |
<ProgressRing>
Animated circular progress indicator
<ProgressRing value={75} size={120} showValue />
| Prop | Type | Required | Description |
|---|---|---|---|
value | number | yes | Progress value (0-100) |
backgroundColor | string | β | Background ring color |
children | ReactNode | β | Custom center content |
className | string | β | Additional CSS classes |
color | string | β | Ring color |
delay | number | β | Delay before starting animation in milliseconds |
duration | number | β | Animation duration in milliseconds |
isActive | boolean | β | Override slide active state |
onComplete | (() => void) | β | Callback when animation completes |
showValue | boolean | β | Show percentage text in center |
size | number | β | Size of the ring in pixels |
strokeWidth | number | β | Stroke width in pixels |
<Quote>
A styled blockquote component
<Quote
author="Albert Einstein"
source="Interview, 1929"
>
"Imagination is more important than knowledge."
</Quote>
| Prop | Type | Required | Description |
|---|---|---|---|
author | string | β | Quote author |
authorStyle | CSSProperties | β | Custom style for the author/figcaption |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
source | string | β | Source or reference |
variant | "default" | "large" | "minimal" | β | Visual variant |
<ScrollableImage>
Displays a scrollable image Perfect for displaying full-page website screenshots that are too tall to fit in a slide.
// Basic scrollable image
<ScrollableImage
src="/screenshots/long-page.png"
alt="Full page screenshot"
maxHeight="70vh"
/>
// With auto-scroll
<ScrollableImage
src="/screenshots/website.png"
alt="Website screenshot"
maxHeight="70vh"
autoScrollSpeed={50}
showIndicators
/>
| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | yes | Alt text for accessibility |
src | string | yes | Image source URL or path |
autoScrollSpeed | number | β | Auto-scroll speed in pixels per second (0 to disable) |
className | string | β | Additional CSS classes |
maxHeight | string | β | Maximum height of the container |
showIndicators | boolean | β | Show scroll indicators |
smoothScroll | boolean | β | Enable smooth scrolling |
<ScrollableImage>
Displays a scrollable image Perfect for displaying full-page website screenshots that are too tall to fit in a slide.
// Basic scrollable image
<ScrollableImage
src="/screenshots/long-page.png"
alt="Full page screenshot"
maxHeight="70vh"
/>
// With auto-scroll
<ScrollableImage
src="/screenshots/website.png"
alt="Website screenshot"
maxHeight="70vh"
autoScrollSpeed={50}
showIndicators
/>
| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | yes | Alt text for accessibility |
src | string | yes | Image source URL or path |
autoScrollSpeed | number | β | Auto-scroll speed in pixels per second (0 to disable) |
className | string | β | Additional CSS classes |
maxHeight | string | β | Maximum height of the container |
showIndicators | boolean | β | Show scroll indicators |
smoothScroll | boolean | β | Enable smooth scrolling |
<Text>
A styled text block component
<Text size="lg" weight="medium">
This is styled body text for your slides.
</Text>
| Prop | Type | Required | Description |
|---|---|---|---|
align | "center" | "left" | "right" | "justify" | β | Text alignment |
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
color | "default" | "primary" | "muted" | "accent" | β | Color variant |
size | "sm" | "md" | "lg" | "xl" | "2xl" | β | Text size |
weight | "medium" | "normal" | "semibold" | "bold" | β | Font weight |
<ThreeColumn>
A three-column layout component
<ThreeColumn
first={<Text>First column</Text>}
second={<Text>Second column</Text>}
third={<Image src="image.jpg" alt="Third column" />}
ratio="1:2:1"
gap="lg"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
first | ReactNode | yes | First column content |
second | ReactNode | yes | Second column content |
third | ReactNode | yes | Third column content |
align | "center" | "start" | "end" | "stretch" | β | Vertical alignment |
className | string | β | Additional CSS classes |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between columns |
ratio | "1:1:1" | "2:1:1" | "1:2:1" | "1:1:2" | "2:2:1" | "1:2:2" | β | Column ratio (e.g., β1:1:1β, β2:1:1β, β1:2:1β) |
responsive | boolean | β | Stack columns on small screens |
<TimelineWithIndicators>
A horizontal timeline component Creates a horizontal timeline with circular indicators linked by a line. Includes labels below each indicator. Perfect for historical overviews and progress tracking.
<TimelineWithIndicators
events={[
{ year: "2020", label: "Founded" },
{ year: "2021", label: "Series A" },
{ year: "2022", label: "Expansion" },
]}
lineColor="#14b8a6"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
events | TimelineEvent[] | yes | Array of event objects with year and label |
className | string | β | Additional CSS classes |
lineColor | string | β | Color of the connecting line |
<TitleSlide>
A centered title slide layout
<TitleSlide
title="Welcome to My Presentation"
subtitle="An Overview of Our Progress"
author="John Doe"
date="January 2025"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
title | ReactNode | yes | Main title |
author | ReactNode | β | Author or presenter name |
className | string | β | Additional CSS classes |
date | ReactNode | β | Date or additional info |
subtitle | ReactNode | β | Subtitle |
<TitleSlideWithElement>
A title slide with a flexible element area
<TitleSlideWithElement
title="Product Launch"
subtitle="Introducing our newest innovation"
element={<Image src="product.png" alt="Product" />}
elementPosition="right"
elementAnimation="fade-in"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
element | ReactNode | yes | Element to display (image, icon, chart, etc.) |
title | ReactNode | yes | Main title |
animationDelay | number | β | Animation delay in milliseconds |
className | string | β | Additional CSS classes |
elementAnimation | ElementAnimation | β | Animation preset for the element |
elementPosition | ElementPosition | β | Position of the element relative to title/subtitle |
subtitle | ReactNode | β | Subtitle |
<TwoColumn>
A two-column layout component
<TwoColumn
left={<Text>Left content</Text>}
right={<Image src="image.jpg" alt="Right image" />}
ratio="2:1"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
left | ReactNode | yes | Left column content |
right | ReactNode | yes | Right column content |
align | "center" | "start" | "end" | "stretch" | β | Vertical alignment |
className | string | β | Additional CSS classes |
gap | "sm" | "md" | "lg" | "xl" | β | Gap between columns |
ratio | "1:1" | "2:1" | "1:2" | "3:2" | "2:3" | β | Column ratio |
<TwoColumnHighlight>
Two-column layout with highlighted sections A layout component featuring two columns with different backgrounds, typically used for section headers or emphasizing key points. The left column is typically darker with a narrower width.
<TwoColumnHighlight
leftContent={<Heading level={1}>Section Title</Heading>}
rightContent={<Text>Description text goes here</Text>}
ratio="1:2"
/>
// With custom colors
<TwoColumnHighlight
leftContent="Key Point"
rightContent="Detailed explanation"
leftBg="#000000"
rightBg="#ffffff"
leftTextColor="#ffffff"
rightTextColor="#000000"
highlightColor="#ff6b35"
/>
| Prop | Type | Required | Description |
|---|---|---|---|
leftContent | ReactNode | yes | Content for the left column |
rightContent | ReactNode | yes | Content for the right column |
className | string | β | Additional CSS classes |
highlight | string | β | Text to highlight in the right column |
highlightColor | string | β | Highlight color for emphasized text |
leftBg | string | β | Left column background color |
leftTextColor | string | β | Left column text color |
ratio | "1:2" | "2:3" | "1:3" | β | Column width ratio (left:right) |
rightBg | string | β | Right column background color |
rightTextColor | string | β | Right column text color |
<TypewriterText>
Text that appears character by character
<TypewriterText speed="medium" cursor>
Hello, World!
</TypewriterText>
| Prop | Type | Required | Description |
|---|---|---|---|
children | string | yes | Text content to animate |
className | string | β | Additional CSS classes |
cursor | boolean | β | Show blinking cursor |
delay | number | β | Delay before starting animation in milliseconds |
isActive | boolean | β | Override slide active state |
onComplete | (() => void) | β | Callback when animation completes |
speed | number | "slow" | "medium" | "fast" | β | Speed of typing in milliseconds per character |
<Video>
A video embedding component
<Video
src="/videos/demo.mp4"
poster="/images/poster.jpg"
title="Product demo video"
autoPlay
loop
muted
/>
| Prop | Type | Required | Description |
|---|---|---|---|
src | string | yes | Video source URL |
autoPlay | boolean | β | Autoplay video |
className | string | β | Additional CSS classes |
controls | boolean | β | Show controls |
fit | "cover" | "contain" | "fill" | β | Object fit mode |
loop | boolean | β | Loop video |
muted | boolean | β | Mute video |
poster | string | β | Poster image |
title | string | β | Accessible title/description for the video |
<WaveLine>
A decorative curved dashed line component Creates a smooth, curved dashed line that spans across a slide to add dynamic visual elements. Perfect for title slide decoration and section separators.
<WaveLine />
<WaveLine color="#00BFA5" dashWidth={3} />
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | β | Children content |
className | string | β | Additional CSS classes |
color | string | β | Color of the dashed line |
dashWidth | number | β | Width of each dash |
<WordReveal>
Text that reveals word by word Note: Import the animations CSS file to use this component: import β@getnarro/shared-ui/styles/animations.cssβ;
<WordReveal animation="blur" staggerDelay={100}>
This text will appear word by word
</WordReveal>
| Prop | Type | Required | Description |
|---|---|---|---|
children | string | yes | Text content to animate (will be split by words) |
animation | WordRevealAnimation | β | Animation type |
className | string | β | Additional CSS classes |
delay | number | β | Delay before starting animation in milliseconds |
duration | number | β | Animation duration per word in milliseconds |
isActive | boolean | β | Override slide active state |
onComplete | (() => void) | β | Callback when all words are revealed |
staggerDelay | number | β | Delay between each word in milliseconds |
<Workflow>
Animated workflow diagram Note: Import the animations CSS file to use this component: import β@getnarro/shared-ui/styles/animations.cssβ;
<Workflow animation="progressive" direction="horizontal">
<WorkflowStep icon="1" title="Start">Begin here</WorkflowStep>
<WorkflowStep icon="2" title="Process">Do the work</WorkflowStep>
<WorkflowStep icon="3" title="Complete">All done!</WorkflowStep>
</Workflow>
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | WorkflowStep children |
animation | WorkflowAnimation | β | Animation type |
className | string | β | Additional CSS classes |
connectorColor | string | β | Connector line color |
direction | WorkflowDirection | β | Layout direction |
highlightActive | boolean | β | Highlight the currently active step |
isActive | boolean | β | Override slide active state |
showConnectors | boolean | β | Show connecting lines/arrows between steps |
staggerDelay | number | β | Delay between each step in milliseconds |
<WorkflowStep>
Individual step in a workflow
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Step content |
className | string | β | Additional CSS classes |
description | string | β | Step description |
icon | ReactNode | β | Icon or number to display |
title | string | β | Step title |
<ZoomImage>
Image with click-to-zoom functionality
<ZoomImage
src="/diagram.png"
alt="Architecture diagram"
zoomable
zoomScale={2}
/>
| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | yes | Alt text for accessibility |
src | string | yes | Image source URL |
className | string | β | Additional CSS classes |
fit | "none" | "cover" | "contain" | "fill" | β | Object fit mode |
height | string | number | β | Height constraint |
rounded | "none" | "sm" | "md" | "lg" | "full" | β | Border radius |
shadow | boolean | β | Add shadow |
width | string | number | β | Width constraint |
zoomable | boolean | β | Enable click-to-zoom |
zoomScale | number | β | Zoom scale factor |