Vistaprint

Base Component

When using the React Visage library, we have a primitive component that is used as the basic building-block for all of our other React Visage components.

Introduction

Typically, React components are built out of plain old HTML elements like <div> and <span>, but by creating our own foundational component, which we've named VisageComponent, we're able to easily share functionality across all of our components without duplicating code.

Here's how we might build a Button component using the standard HTML <button> tag:

jsx
function Button(props) {
return <button {...props} />
}

This Button forwards all props directly to the underlying <button>, so our Button implicitly understands all of <button>'s props (e.g. onClickclassName, etc.)

jsx
<Button onClick={() => alert('clicked!')}>Click me!</Button>

We can take that a step further though. Let's take a look at how we might build a Button component using VisageComponent:

jsx
function Button(props) {
return <VisageComponent component="button" {...props} />
}

Just like before, any props passed to Button will be forwarded to the underlying component. But rather than using a <button> as the underlying component, we use our VisageComponent. So, this Button understands all props that VisageComponent understands.

And if we take a look at a simple implementation of VisageComponent:

jsx
function VisageComponent(props) {
const { component, ...otherProps } = props
// we need to rename to an uppercase variable or else JSX gets mad
const Comp = component
return <Comp {...otherProps} />
}

Our VisageComponent renders whatever is passed via the component prop and forwards all of its props to that component.

So, if you think about it, we're actually in the same position that we were in before.

Our first Button just passed all props directly to a <button> and, by doing so, gained an implicit understanding of all of <button>s props. And our second Button passes all of its props to VisageComponent which passes all of its props to a <button>, so we still get that implicit understanding of all of <button>'s props, but--crucially--VisageComponent gets to look at the props before they get to the <button>.

This allows us to intercept those props and to do whatever we want!

Shared Functionality

This enables us, for example, to effectively add a prop to every one of our components by simply adding that prop to VisageComponent.

Let's say that we want all of our components to have a prop called shouldRenderAnEmoji. If we pass shouldRenderAnEmoji to any component, that component should render an emoji rather than whatever else it was going to render. Very useful.

Now, we could go and add that logic to all 60+ of our components, or we could just add it VisageComponent!

Let's update our VisageComponent to add the functionality:

jsx
function VisageComponent(props) {
const { component, shouldRenderAnEmoji, ...otherProps } = props
const Comp = component
if (shouldRenderAnEmoji) {
return <Comp>😅</Comp>
}
return <Comp {...otherProps} />
}

Now, any component that was built with VisageComponent will implicitly understand the shouldRenderAnEmoji prop!

jsx
<Button shouldRenderEmoji /> // <button>😅</button>

The rest of this article will cover all of the shared functionality that we've currently built in to VisageComponent.

Component Prop

As we've seen, VisageComponent accepts a prop called component that allows you to specify exactly which component should be rendered. Each of our components (e.g. TextButtonCollapsible, etc.) provide a default value for component, but if you provide you pass a value for the component prop yourself, your value will override the default component!

jsx
// TextButton uses component="button" by default
// but you can easily pass your own value for `component`!
// note how we pass an `href` now that we know that an `<a>` is going to be rendered!
;<TextButton component="a" href="/">
All the styles from TextButton, but is actually using an anchor tag!
</TextButton>

The component prop provides a way to override the default component that is rendered when you use any of the React Visage components. The component prop accepts any HTML tag name (e.g. component="div") or any React component (e.g. component={ReactRouterLink}).

Semantics

In the world of HTML, semantics are of utmost importance.

Creating semantically-correct markup has a few key benefits:

  1. Accessibility - screen-readers and other assistive technologies are able to better understand semantic pages which results in a much better experience for folks who use those tools

  2. SEO - site-traversing bots (like Google's "spiders") are able to better understand semantic pages which can result in better search engine ranking

  3. Developer Experience (DX) - Semantic HTML is easier to read/maintain/navigate which can actually speed up development

By default, the React Visage will render the most semantically-correct HTML that it can. e.g. TextButton will render a button and Link will render an a tag, but there are often cases where the proper HTML is based on context to which React Visage does not have access.

That is why we provide the component prop!

Here, we'll provide a few examples of where you might apply the component prop.

Grid Example

GridContainerRow, and Column typically don't carry any semantic meaning; they're just used for layout, so they render divs by default.

However, if we were rendering a list of items in a shopping cart where each item was in its own Row, then our GridContainer is semantically a list and each Row is a list-item.

Using the component prop, we can easily encode that information

jsx
<GridContainer component="ul">
<Row component="li">
<Column span={12}>Cart item 1</Column>
</Row>
<Row component="li">
<Column span={12}>Cart item 2</Column>
</Row>
</GridContainer>

Just like that, we've improved the screen-reader experience dramatically by allowing screen-reading tools to announce this section of the page as "a list containing 2 items" rather than "err I don't know what this part of the page is; it's just a bunch of divs" (disclaimer: these are not actually screen-reader quotes)

Other props

The React Visage base component also adds these props to all React components: