Build Custom Components
Create reusable UI components in React, Vue, or Svelte. Each component includes a schema file that defines which props are editable in the page builder. Your marketing team gets a visual editor to update content, while you maintain full control over design and behavior.
How Components Work
Component File
Your component code with props that accept content from the page builder.
Schema File
JSON that tells Oaysus which props are editable and how to render the editor UI.
When you push components, Oaysus reads the schema and automatically generates form fields in the page builder. Marketing edits content visually, and your component renders it live.
Framework Examples
1interface HeroBannerProps {
2 heading: string
3 subheading: string
4 buttonText: string
5 buttonLink: string
6 backgroundImage?: string
7 overlayOpacity?: number
8}
9
10export default function HeroBanner({
11 heading = 'Welcome to Our Site',
12 subheading = 'Build something amazing with Oaysus',
13 buttonText = 'Get Started',
14 buttonLink = '/',
15 backgroundImage,
16 overlayOpacity = 0.5
17}: HeroBannerProps) {
18 return (
19 <section
20 className="relative py-24 px-6 text-white"
21 style={{
22 backgroundImage: backgroundImage ? `url(${backgroundImage})` : undefined,
23 backgroundSize: 'cover',
24 backgroundPosition: 'center'
25 }}
26 >
27 {backgroundImage && (
28 <div
29 className="absolute inset-0 bg-black"
30 style={{ opacity: overlayOpacity }}
31 />
32 )}
33 <div className="relative max-w-4xl mx-auto text-center">
34 <h1 className="text-5xl font-bold mb-4">{heading}</h1>
35 <p className="text-xl mb-8 opacity-90">{subheading}</p>
36 <a
37 href={buttonLink}
38 className="inline-block bg-white text-gray-900 px-8 py-3 rounded-lg font-medium hover:bg-gray-100 transition-colors"
39 >
40 {buttonText}
41 </a>
42 </div>
43 </section>
44 )
45}1{
2 "displayName": "Hero Banner",
3 "category": "marketing",
4 "props": {
5 "heading": {
6 "type": "string",
7 "label": "Heading",
8 "default": "Welcome to Our Site"
9 },
10 "subheading": {
11 "type": "string",
12 "label": "Subheading",
13 "default": "Build something amazing with Oaysus"
14 },
15 "buttonText": {
16 "type": "string",
17 "label": "Button Text",
18 "default": "Get Started"
19 },
20 "buttonLink": {
21 "type": "string",
22 "label": "Button Link",
23 "default": "/"
24 },
25 "backgroundImage": {
26 "type": "image",
27 "label": "Background Image"
28 },
29 "overlayOpacity": {
30 "type": "number",
31 "label": "Overlay Opacity",
32 "default": 0.5,
33 "min": 0,
34 "max": 1,
35 "step": 0.1
36 }
37 }
38}Schema Field Types
stringSingle line text
textMulti-line text
numberNumeric value
booleanTrue/false toggle
colorHex color value
imageImage from media library
arrayRepeatable list of items
selectDropdown with options
Field Options
labelDisplay name shown in the editor. If omitted, the prop name is used.defaultInitial value when the component is added to a page.requiredIf true, the field must have a value before publishing.optionsFor select type: array of { value, label } objects.min / max / stepFor number type: constrain the input range.itemSchemaFor array type: defines the shape of each item in the list.Best Practices
TypeScriptDefine prop interfaces to catch type mismatches between your component and schema.
DefaultsComponents should render something meaningful even with default props.
ImagesHandle missing images with conditional rendering or fallback backgrounds.
TailwindUse Tailwind classes. Avoid custom CSS files that won't be loaded.
FocusOne component per concern. Don't build Swiss army knives.
Component Categories
Set the category field in your schema to organize components in the page builder: