Closed Components
Learn how to create reusable components using the example of an avatar
Motivation
Writing a few lines of code every time you need a simple Avatar
is tedious. Creating a dedicated
component encapsulates logic, simplifies the API, ensures consistent usage, and maintains clean
code. This approach enhances reusability, making the component easier to maintain and test.
Here's an example of an Avatar
component that can be used consistently across your application:
import { UserIcon } from 'lucide-react'
import { forwardRef } from 'react'
import { Avatar as ArkAvatar } from '@ark-ui/react'
export interface AvatarProps extends ArkAvatar.RootProps {
name?: string
src?: string
}
export const Avatar = forwardRef<HTMLDivElement, AvatarProps>((props, ref) => {
const { name, src, ...rootProps } = props
return (
<ArkAvatar.Root ref={ref} {...rootProps}>
<ArkAvatar.Fallback>{getInitials(name) || <UserIcon />}</ArkAvatar.Fallback>
<ArkAvatar.Image src={src} alt={name} />
</ArkAvatar.Root>
)
})
const getInitials = (name = '') =>
name
.split(' ')
.map((part) => part[0])
.slice(0, 2)
.join('')
.toUpperCase()
import { UserIcon } from 'lucide-solid'
import { Show, splitProps } from 'solid-js'
import { Avatar as ArkAvatar } from '@ark-ui/solid'
export interface AvatarProps extends ArkAvatar.RootProps {
name?: string
src?: string
}
export const Avatar = (props: AvatarProps) => {
const [localProps, rootProps] = splitProps(props, ['name', 'src'])
return (
<ArkAvatar.Root {...rootProps}>
<ArkAvatar.Fallback>
<Show when={localProps.name} fallback={<UserIcon />}>
{getInitials(localProps.name)}
</Show>
</ArkAvatar.Fallback>
<ArkAvatar.Image src={localProps.src} alt={localProps.name} />
</ArkAvatar.Root>
)
}
const getInitials = (name = '') =>
name
.split(' ')
.map((part) => part[0])
.splice(0, 2)
.join('')
.toUpperCase()
<script setup lang="ts">
import { computed } from 'vue'
import { Avatar, type AvatarRootEmits, type AvatarRootProps, useForwardPropsEmits } from '@ark-ui/vue'
export interface AvatarProps extends AvatarRootProps {
src?: string
name: string
}
const props = defineProps<AvatarProps>()
const emits = defineEmits<AvatarRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
const getInitials = computed(() =>
props.name
.split(' ')
.map((part) => part[0])
.slice(0, 2)
.join('')
.toUpperCase(),
)
</script>
<template>
<Avatar.Root v-bind="forwarded">
<Avatar.Fallback>{{ getInitials }}</Avatar.Fallback>
<Avatar.Image :src="props.src" :alt="props.name" />
</Avatar.Root>
</template>
Usage
To use the Avatar
component, pass the name
and src
props as shown below:
<Avatar name="Christian" src="https://avatars.githubusercontent.com/u/1846056?v=4" />