Chapter 4: Display
Formatting Components
SmartCommon provides components to display data in a formatted and consistent way.
String
Display short text.
import { String } from '@cap-rel/smartcommon';
<String value="John Doe" />
<String value={user.name} fallback="Not specified" />
// With truncation
<String value={longText} maxLength={50} />
Text
Display long text with line breaks preserved.
import { Text } from '@cap-rel/smartcommon';
<Text value={product.description} />
// With line limit
<Text value={description} maxLines={3} />
Number
Display formatted number according to locale.
import { Number } from '@cap-rel/smartcommon';
// Simple number
<Number value={1234.56} />
// Displays: 1,234.56
// With fixed decimals
<Number value={99.9} decimals={2} />
// Displays: 99.90
// Price
<Number value={29.99} suffix=" €" />
// Displays: 29.99 €
// Percentage
<Number value={0.156} format="percent" />
// Displays: 15.6%
Datetime
Display formatted date and time.
import { Datetime } from '@cap-rel/smartcommon';
// Full date
<Datetime value="2024-03-15T14:30:00" />
// Displays: March 15, 2024 at 2:30 PM
// Date only
<Datetime value="2024-03-15" format="date" />
// Displays: March 15, 2024
// Time only
<Datetime value="2024-03-15T14:30:00" format="time" />
// Displays: 2:30 PM
// Short format
<Datetime value="2024-03-15" format="short" />
// Displays: 03/15/2024
// Relative format
<Datetime value="2024-03-15T14:30:00" format="relative" />
// Displays: 2 days ago
Duration
Display duration.
import { Duration } from '@cap-rel/smartcommon';
// Duration in seconds
<Duration value={3661} />
// Displays: 1h 1min 1s
// Duration in minutes
<Duration value={90} unit="minutes" />
// Displays: 1h 30min
// Compact format
<Duration value={3600} format="compact" />
// Displays: 1:00:00
Display email with clickable link.
import { Email } from '@cap-rel/smartcommon';
<Email value="contact@example.com" />
// Creates a mailto link
<Email value={user.email} showIcon />
Url
Display URL with clickable link.
import { Url } from '@cap-rel/smartcommon';
<Url value="https://example.com" />
<Url value={product.website} label="View website" />
<Url value={link} openInNewTab />
PhoneNumber
Display clickable phone number.
import { PhoneNumber } from '@cap-rel/smartcommon';
<PhoneNumber value="+33612345678" />
// Displays: +33 6 12 34 56 78 (formatted)
// Creates a tel: link
<PhoneNumber value={contact.phone} showIcon />
Address
Display formatted address.
import { Address } from '@cap-rel/smartcommon';
<Address
value={{
street: '15 rue de la Paix',
city: 'Paris',
zip: '75002',
country: 'France'
}}
/>
// With Google Maps link
<Address value={customer.address} showMap />
Coordinates
Display GPS coordinates.
import { Coordinates } from '@cap-rel/smartcommon';
<Coordinates value={{ lat: 48.8566, lng: 2.3522 }} />
// With map link
<Coordinates value={location} showMap />
Color
Display a color.
import { Color } from '@cap-rel/smartcommon';
<Color value="#FF5733" />
// Displays color square + code
<Color value={product.color} showCode={false} />
// Displays only the square
Icon
Display icon.
import { Icon } from '@cap-rel/smartcommon';
<Icon name="home" />
<Icon name="check" size={24} color="green" />
// With react-icons
import { FiCheck, FiX } from 'react-icons/fi';
<Icon component={FiCheck} color="green" />
<Icon component={FiX} color="red" />
Tags
Display multiple tags.
import { Tags } from '@cap-rel/smartcommon';
<Tags value={['React', 'JavaScript', 'TypeScript']} />
<Tags
value={product.categories}
color="blue"
/>
Tag
Single tag.
import { Tag } from '@cap-rel/smartcommon';
<Tag>New</Tag>
<Tag color="green">Active</Tag>
<Tag color="red">Urgent</Tag>
// With icon
import { FiCheck } from 'react-icons/fi';
<Tag icon={FiCheck} color="green">Validated</Tag>
Files
Display files with download.
import { Files } from '@cap-rel/smartcommon';
<Files
value={[
{ name: 'document.pdf', url: '/files/doc.pdf', size: 1024000 },
{ name: 'image.jpg', url: '/files/img.jpg', size: 512000 }
]}
/>
Signature
Display a signature.
import { Signature } from '@cap-rel/smartcommon';
<Signature value={contract.signature} />
List and ListItem
Display lists.
import { List, ListItem } from '@cap-rel/smartcommon';
import { useNavigation } from '@cap-rel/smartcommon';
function ProductsList({ products }) {
const nav = useNavigation();
return (
<List>
{products.map(product => (
<ListItem
key={product.id}
title={product.label}
subtitle={`${product.price} €`}
image={product.thumbnail}
onClick={() => nav.navigate(`/products/${product.id}`)}
chevron
/>
))}
</List>
);
}
ListItem Props
| Prop | Type | Description |
|---|---|---|
| title | string | Main title |
| subtitle | string | Subtitle |
| image | string | Image URL |
| icon | Component | Icon on the left |
| onClick | function | Click action |
| chevron | boolean | Show right arrow |
| actions | ReactNode | Actions on the right |
Button
Action button.
import { Button } from '@cap-rel/smartcommon';
// Variants
<Button>Default</Button>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="danger">Danger</Button>
<Button variant="ghost">Ghost</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="md">Normal</Button>
<Button size="lg">Large</Button>
// States
<Button loading>Loading</Button>
<Button disabled>Disabled</Button>
// With icon
import { FiPlus } from 'react-icons/fi';
<Button icon={FiPlus}>Add</Button>
Spinner
Loading indicator.
import { Spinner } from '@cap-rel/smartcommon';
<Spinner />
<Spinner size="sm" />
<Spinner size="lg" />
// Loading page
function LoadingPage() {
return (
<div className="flex items-center justify-center h-screen">
<Spinner size="lg" />
</div>
);
}
Complete Example: Product Detail
import {
Page,
Block,
String,
Text,
Number,
Datetime,
Tags,
Tag,
Files,
Button,
Carousel,
CarouselItem
} from '@cap-rel/smartcommon';
import { useNavigation } from '@cap-rel/smartcommon';
export const ProductDetailPage = ({ product }) => {
const nav = useNavigation();
return (
<Page title={product.label}>
{/* Photos */}
{product.photos?.length > 0 && (
<Carousel>
{product.photos.map((photo, index) => (
<CarouselItem key={index}>
<img src={photo.url} alt={`Photo ${index + 1}`} />
</CarouselItem>
))}
</Carousel>
)}
{/* Main Information */}
<Block>
<div className="flex justify-between items-start">
<div>
<h1 className="text-2xl font-bold">
<String value={product.label} />
</h1>
<Tags value={product.categories} />
</div>
<Tag color={product.isActive ? 'green' : 'gray'}>
{product.isActive ? 'Active' : 'Inactive'}
</Tag>
</div>
<div className="mt-4 text-3xl font-bold text-primary">
<Number value={product.price} suffix=" €" />
</div>
</Block>
{/* Description */}
<Block title="Description">
<Text value={product.description} />
</Block>
{/* Details */}
<Block title="Details">
<dl className="space-y-2">
<div className="flex justify-between">
<dt className="text-gray-500">Reference</dt>
<dd><String value={product.ref} /></dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">Stock</dt>
<dd><Number value={product.stock} /></dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">Created on</dt>
<dd><Datetime value={product.createdAt} format="date" /></dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">Modified on</dt>
<dd><Datetime value={product.updatedAt} format="relative" /></dd>
</div>
</dl>
</Block>
{/* Documents */}
{product.documents?.length > 0 && (
<Block title="Documents">
<Files value={product.documents} />
</Block>
)}
{/* Actions */}
<Block>
<div className="flex gap-2">
<Button
variant="outline"
onClick={() => nav.navigate(`/products/${product.id}/edit`)}
>
Edit
</Button>
<Button variant="primary">
Order
</Button>
</div>
</Block>
</Page>
);
};
Key Points to Remember
- Formatting components for consistent display
- Number with automatic French locale
- Datetime with practical relative formats
- List/ListItem for navigable lists
- Button with variants and states
Previous Chapter | Back to Module | Next Module: SmartCommon Hooks ->