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.jsxAudio.jsxButton.jsxContents.jsxFooter.jsxHeader.jsxImage.jsxRichText.jsxVideo.jsxWrapper.jsx
Component Categories
Navigation and Actions
AppLinkButton
Content Rendering
ContentsRichTextWrapper
Media Placeholders
ImageVideoAudio
Shell Components
HeaderFooter
AppLink
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:
todata-routeronMouseEnteronFocus- any normal link props such as
className,target, orrel
to can be:
- a string path
- a React Router location-like object with
pathname,search, andhash
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
toand nohref-> renders a<button> - external
hrefortosuch ashttps://,mailto:, ortel:-> renders a normal<a> - internal
toorhref-> rendersAppLink
Useful props:
tohreftextchildrenbeforeaftervariantclassName- any normal button or link props such as
type,target,rel, ordata-router
Important defaults and behavior:
variantdefaults toprimarytextis used when present, otherwisechildrenbecomes the main labelbeforeandafterrender inside.button__beforeand.button__after- if
before,after, ortextare 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:
uptitletitlesubtitletextbuttonstitleTagclassName- any other props you want forwarded to the outer
.contentsnode
Important defaults and behavior:
titleTagdefaults toh2- if every content prop is empty,
Contentsreturnsnull textis rendered throughWrapper, not directly throughRichTextbuttonsis mapped throughButton- each button object can use either
toorurl new_tabis converted totarget="_blank"whentargetis 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:
texttourlhreftargetnew_tabbeforeaftervariantdata-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
valuereturnsnull classNamedefaults 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 > .imgVideo->.video-container > .inner-video > .videoAudio->.audio-container > .inner-audio > .audio
Useful props:
className- forwarded DOM props such as
id,data-*, oraria-* - 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
Header is a shell-level component rendered from React, but mounted outside the smoother through a portal.
Useful props:
showclassNamemountId- any other props you want forwarded to the final
<header>node
Important behavior:
- if
showisfalse, it renders nothing - if
showistrue, it portals into the element identified bymountId - default
mountIdisapp-header - the mount node should live outside
#pageWrapperand#pageContent - if the mount node is missing, it falls back to
document.body
Important limitation of the shipped component:
- the default
Header.jsxis 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
Footer is simpler than Header.
Useful props:
showclassName- any other props you want forwarded to the
<footer>node
Important behavior:
- if
showisfalse, it renders nothing - if
showistrue, 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.