Skip to main content

Components

Role

src/themes/reactwp/js/components/ contains the reusable React building blocks shipped with the starter.

These components are intentionally small. They are not a design system by themselves. Their job is to cover the core patterns ReactWP needs often:

  • internal links with route prefetching
  • button rendering
  • rich text output
  • editorial content blocks
  • media placeholders for the loader runtime
  • shell-level header and footer mounting

Available Components

  • AppLink.jsx
  • Audio.jsx
  • Button.jsx
  • Contents.jsx
  • Footer.jsx
  • Header.jsx
  • Image.jsx
  • RichText.jsx
  • Video.jsx
  • Wrapper.jsx

Component Categories

  • AppLink
  • Button

Content Rendering

  • Contents
  • RichText
  • Wrapper

Media Placeholders

  • Image
  • Video
  • Audio

Shell Components

  • Header
  • Footer

AppLink is the base component for internal navigation.

It wraps react-router-dom's Link, but also prefetches the next route on hover and focus through the loader runtime.

Use it when:

  • you are linking to an internal route
  • you want React navigation and transitions
  • you want route prefetching

Useful props:

  • to
  • data-router
  • onMouseEnter
  • onFocus
  • any normal link props such as className, target, or rel

to can be:

  • a string path
  • a React Router location-like object with pathname, search, and hash

If data-router="false" or data-router={false} is passed, AppLink falls back to a normal <a> instead of React Router. In that mode it does not use the route prefetch behavior.

Example:

import AppLink from '../components/AppLink';

const Example = () => {
return <AppLink to="/">Home</AppLink>;
};

Example without router interception:

<AppLink to="/wp-admin/" data-router={false}>
Open WordPress Admin
</AppLink>

Button

Button is the main action component.

It chooses the correct underlying element automatically:

  • no to and no href -> renders a <button>
  • external href or to such as https://, mailto:, or tel: -> renders a normal <a>
  • internal to or href -> renders AppLink

Useful props:

  • to
  • href
  • text
  • children
  • before
  • after
  • variant
  • className
  • any normal button or link props such as type, target, rel, or data-router

Important defaults and behavior:

  • variant defaults to primary
  • text is used when present, otherwise children becomes the main label
  • before and after render inside .button__before and .button__after
  • if before, after, or text are strings, they are rendered as HTML strings

Examples:

<Button onClick={handleClick}>Open modal</Button>
<Button to="/contact/" variant="primary">
Contact us
</Button>
<Button
href="https://example.com"
before="Read"
after="now"
>
External article
</Button>
<Button href="/wp-admin/" data-router={false}>
Open WordPress Admin
</Button>

Contents

Contents is a convenience content block for common editorial layouts.

It can render:

  • an uptitle
  • a title
  • a subtitle
  • text
  • a list of buttons

Useful props:

  • uptitle
  • title
  • subtitle
  • text
  • buttons
  • titleTag
  • className
  • any other props you want forwarded to the outer .contents node

Important defaults and behavior:

  • titleTag defaults to h2
  • if every content prop is empty, Contents returns null
  • text is rendered through Wrapper, not directly through RichText
  • buttons is mapped through Button
  • each button object can use either to or url
  • new_tab is converted to target="_blank" when target is not already provided

titleTag is useful when the same content pattern needs different document semantics.

Examples:

<Contents
uptitle="ReactWP"
title="Project overview"
subtitle="Start from a clean baseline"
titleTag="h1"
text="<p>Start by customizing your templates, site settings, and frontend runtime.</p>"
/>
<Contents
title="Section title"
titleTag="h3"
text="<p>This can also be a subsection inside a longer page.</p>"
/>
<Contents
uptitle="ReactWP"
title="Project overview"
subtitle="Start from a clean baseline"
text="<p>Start by customizing your templates, site settings, and frontend runtime.</p>"
buttons={[
{
text: 'Open home',
to: '/'
},
{
text: 'Open admin',
href: '/wp-admin/',
data-router: false,
new_tab: true
}
]}
/>

Button objects are forwarded to Button.jsx. In practice, the most useful keys are:

  • text
  • to
  • url
  • href
  • target
  • new_tab
  • before
  • after
  • variant
  • data-router

RichText

RichText is the simplest way to render a stored HTML string.

If value is a string, it is rendered with dangerouslySetInnerHTML.

If value is already a React node, it is rendered directly inside a <div>.

Important behavior:

  • falsy value returns null
  • className defaults to an empty string

Example:

<RichText
className="copy"
value="<p>This content comes from WordPress or ACF.</p>"
/>

Use it when you explicitly want raw HTML output without the custom rwp-wrap element.

Wrapper

Wrapper renders a custom <rwp-wrap> element around value.

Useful props:

  • value
  • any other props you want forwarded to <rwp-wrap>

Example:

<Wrapper value={text} />

This is mainly useful when the project styles or scripts rely on that wrapper element.

If you do not need that custom wrapper behavior, RichText is usually the simpler choice.

Image, Video, and Audio

These components are placeholder containers, not classic media tags with src props.

They render the shell expected by the loader runtime:

  • Image -> .img-container > .inner-img > .img
  • Video -> .video-container > .inner-video > .video
  • Audio -> .audio-container > .inner-audio > .audio

Useful props:

  • className
  • forwarded DOM props such as id, data-*, or aria-*
  • forwarded ref

Example:

<Image className="hero-media" />

These components make the most sense when your project uses ReactWP's critical or non-critical media pipelines.

They are useful because the loader can swap the placeholder with the real media node later, after preloading.

Header is a shell-level component rendered from React, but mounted outside the smoother through a portal.

Useful props:

  • show
  • className
  • mountId
  • any other props you want forwarded to the final <header> node

Important behavior:

  • if show is false, it renders nothing
  • if show is true, it portals into the element identified by mountId
  • default mountId is app-header
  • the mount node should live outside #pageWrapper and #pageContent
  • if the mount node is missing, it falls back to document.body

Important limitation of the shipped component:

  • the default Header.jsx is only an empty shell
  • it does not render navigation, site data, or branding on its own
  • any extra props you pass are spread directly onto the final <header> element unless you customize the component

That means if you want to pass navigation, site, or other runtime data, you should edit Header.jsx to consume those props explicitly instead of blindly forwarding them to the DOM.

Example shell usage:

<AppShell
showHeader={true}
headerProps={{
className: 'site-header',
mountId: 'app-header'
}}
>
{children}
</AppShell>

If your header needs menu data, a more realistic pattern is:

const Header = ({
show,
className,
mountId = 'app-header',
navigation = {},
...domProps
}) => {
if(!show){
return null;
}

return createPortal(
<header className={className} {...domProps}>
<Navigation navigation={navigation} />
</header>,
document.getElementById(mountId)
);
};

If you use a custom mountId, the matching node must exist in the PHP markup:

<div id="my-header-mount"></div>

For the shell structure that makes this work, see Theme Shell and Scroll.

Footer is simpler than Header.

Useful props:

  • show
  • className
  • any other props you want forwarded to the <footer> node

Important behavior:

  • if show is false, it renders nothing
  • if show is true, it renders an empty <footer> shell
  • like Header, the shipped version does not render any actual content by itself

Example:

<AppShell
showFooter={true}
footerProps={{
className: 'site-footer'
}}
>
{children}
</AppShell>

In practice, most projects will customize Footer.jsx quickly.