Creating a full viewport component
You can create a Frontastic component that takes up the full viewport of a browser (also known as full-bleed). Let's look at an example of how to do this.
Below is an example of a hero Frontastic component. The image can either be the full width of the grid, or the full width of the viewport.
Full width of grid (12-column layout element) | Full width of viewport (full-bleed) |
---|---|
![]() | ![]() |
Let's build a simplified example:
As always, we start with the schema. We'll create a text field and a toggle so users of the Frontastic studio can turn our full-bleed image feature on and off.
{
"tasticType": "frontastic/examples/hero",
"name": "Hero",
"icon": "image",
"category": "content",
"schema": [
{
"name": "Content",
"fields": [
{
"label": "Image",
"field": "image",
"type": "media"
},
{
"label": "Full-bleed?",
"field": "isFullBleed",
"type": "boolean",
"required": true,
"default": true
},
{
"label": "Aspect ratio",
"field": "aspect",
"type": "enum",
"default": "16/9",
"values": [
{
"value": "original",
"name": "Original"
},
{
"value": "16/9",
"name": "16:9"
},
{
"value": "4/3",
"name": "4:3"
},
{
"value": "21/9",
"name": "21:9"
}
]
}
]
}
]
}
Add this schema to the Frontastic studio.
Next, we need to create our tastic.jsx
file to receive the information from the schema.
import React from 'react'
import PropTypes from 'prop-types'
import Hero from '../../../patterns/molecules/Hero'
import tastify from '@frontastic/catwalk/src/js/helper/tastify'
const HeroTastic = ({ data }) => {
return <Hero {...data} />
}
HeroTastic.propTypes = {
data: PropTypes.object.isRequired,
}
export default tastify({ translate: true })(HeroTastic)
Then, we create a wrapper component and add it to our layout folder. This is a simple React Component that makes sure its contents (the children) fill up the whole horizontal viewport space. To accomplish this, we use a little CSS trick.
import React from 'react'
import PropTypes from 'prop-types'
export default function FullPageWidthWrapper ({ children, className = '' }) {
return (
<div
className={className}
style={{
width: '100vw',
position: 'relative',
left: '50%',
right: '50%',
marginLeft: '-50vw',
marginRight: '-50vw',
}}
>
{children}
</div>
)
}
FullPageWidthWrapper.propTypes = {
children: PropTypes.any,
className: PropTypes.string,
}
We can now use the wrapper to wrap the contents of our component if the users of the Frontastic studio choose to do so using the toggle. We do this in the index.tsx
of the component.
import React from 'react'
import PropTypes from 'prop-types'
import MediaImage from '@frontastic/catwalk/src/js/mediaImage'
import FullPageWidthWrapper from '../Layout/FullPageWidthWrapper'
const Hero = ({ image, aspect, isFullBleed }) => {
const aspectClass = {
'original': '',
'16/9': 'pb-16/9',
'4/3': 'pb-4/3',
'21/9': 'pb-21/9',
}
const calculateAspectStyle = (aspect, img) => {
if (aspect === 'original' && img) {
return { paddingBottom: '${(img.media.height / img.media.width) * 100}%'}
}
return {}
}
const content = (
<div className={'relative ${aspectClass[aspect]}'} style={{...calculateAspectStyle(aspect, image)}}>
<MediaImage
className={'w-${isFullBleed ? 'full' : 'auto'} absolute'}
media={image}
/>
</div>
)
if (isFullBleed) {
return <FullPageWidthWrapper>{content}</FullPageWidthWrapper>
}
return content
}
Hero.propTypes = {
image: PropTypes.object.isRequired,
aspect: PropTypes.string.isRequired,
isFullBleed: PropTypes.bool.isRequired,
}
export default Hero
And that's it. When this component is added to a page version in the Frontastic studio, you can now select the image and if it's full-bleed or not:
If you add another Frontastic component to the same layout element, it could cause your layout to break. Either keep it in a separate layout element or update your CSS to stop this from happening.
Updated 9 months ago