strapi-design-extended
v0.0.13
Published
Build upon the @strapi/design-system to add a few more components
Readme
Strapi Design Extended
Note: This project is currently a work in progress (WIP). The collection contains initial components and hooks, with additional utilities planned.
strapi-design-extended extends the existing @strapi/design-system with additional React components and hooks.
Please note that this package is a developer library intended for use within other Strapi plugins or customized Strapi configurations; it is not a standalone Strapi plugin.
Vite Optimization Note: To use this package successfully in your Strapi project, you must instruct Vite not to optimize
strapi-design-extended. Add or merge the following configuration in./src/admin/vite.config.ts(or yours/the example one) within the admin configuration of your Strapi project:import { mergeConfig, type UserConfig } from "vite"; export default (config: UserConfig) => { return mergeConfig(config, { optimizeDeps: { exclude: ["strapi-design-extended"], }, }); };
Interactive documentation and component previews are available in the Storybook.
Built with React, TypeScript, and bundled using Vite.
Features & Current Capabilities
1. Components
SegmentedControl
A control component based on Radix UI's ToggleGroup primitive, designed to match the Strapi design tokens and visual style.
- Auto-selection: If no string
valueordefaultValueis provided, it select the first available item. - Strict Single-selection: Clicking the already-selected item does not deselect it, ensuring a selection remains active.
- Disabled State: Supports standard Radix and design system disabled attributes on item buttons.
SegmentedControl Usage
import { SegmentedControl } from 'strapi-design-extended';
function MyApp() {
return (
<SegmentedControl.Root defaultValue="1" onChange={(val) => console.log(val)}>
<SegmentedControl.Item value="1">Option 1</SegmentedControl.Item>
<SegmentedControl.Item disabled value="2">
Option 2
</SegmentedControl.Item>
<SegmentedControl.Item value="3">Option 3</SegmentedControl.Item>
</SegmentedControl.Root>
);
}Sheet
A highly flexible slide-out drawer/panel component based on Radix UI's Dialog primitive, designed to match modern design layouts and visual styling.
- Granular Composition: Leverages multiple sub-components (
Sheet.Root,Sheet.Trigger,Sheet.Content,Sheet.Body,Sheet.Footer,Sheet.Title,Sheet.Close) for deep customizability of templates and content layout. - Positioning Support: Supports sliding drawers in from any side of the viewport:
right(default),left,top, orbottomvia thesideprop. - Sizing Control: Allows developers to adjust the
widthof side sheets (when utilizingleftorrightpositioning) and theheightof top/bottom sheets dynamically. - Accessibility & Animations: Seamlessly integrates focus trapping and close triggers (supporting outside backdrop click and the Escape key) combined with custom entry and exit animations.
Sheet Composable Usage
import { Sheet } from 'strapi-design-extended';
import { Button, Typography } from '@strapi/design-system';
function MyApp() {
return (
<Sheet.Root>
<Sheet.Trigger>Open Sheet</Sheet.Trigger>
<Sheet.Content side="right" width="440px">
<Sheet.Title>Sheet Title</Sheet.Title>
<Sheet.Body>
<Typography variant="pi">This is the content of the sheet panel.</Typography>
</Sheet.Body>
<Sheet.Footer>
<Sheet.Close asChild>
<Button variant="secondary">Close</Button>
</Sheet.Close>
</Sheet.Footer>
</Sheet.Content>
</Sheet.Root>
);
}SheetDialog
A simplified, props-driven packaging of the Sheet component for clean, boilerplate-free overlay implementations.
- Props-centric: Exposes properties like
title,side,width,height, andactionButtonsdirectly, wrapping child content and boilerplate layout automatically. - Controlled Flow: Simple
openstate andonClosecallback trigger are bundled inside to facilitate streamlined modal dialog lifecycle management.
SheetDialog Usage
import React, { useState } from 'react';
import { SheetDialog } from 'strapi-design-extended';
import { Button, Typography } from '@strapi/design-system';
function MyApp() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open Dialog</Button>
<SheetDialog
open={open}
showClose={true}
onClose={() => setOpen(false)}
title="Sheet Title"
side="right"
width="440px"
actionButtons={
<Button variant="secondary" onClick={() => setOpen(false)}>
Close
</Button>
}
>
<Typography variant="pi">This is the content inside the SheetDialog wrapper.</Typography>
</SheetDialog>
</>
);
}Slider
A slider component based on Radix UI's Slider primitive, designed to match the Strapi design tokens and visual style.
- Single or Range Selection: Supports single-value selections or multi-thumb range selections depending on the size of the array passed to
valueordefaultValue. - Customizable: Configurable minimum (
min), maximum (max), and step (step) increments. - Design Token Integration: Integrates with Strapi's design tokens using
useDesignTokens.
Slider Usage
import { Slider } from 'strapi-design-extended';
function MyApp() {
return (
<div style={{ width: '500px' }}>
{/* Single Value Slider */}
<Slider defaultValue={[20]} label="Simple Slider" />
{/* Range Slider */}
<Slider defaultValue={[20, 80]} label="Range Slider" />
</div>
);
}HoverCard / HoverElement
A hover-card component based on Radix UI's HoverCard primitive, styled to match the Strapi design system.
- Composition (
HoverCard): Exposes sub-components (HoverCard.Root,HoverCard.Trigger,HoverCard.Content) for modular markup layout. - Props-based wrapper (
HoverElement): A shortcut component that accepts atriggernode and child elements directly. - Animations: Directional transitions and fades that align with the active anchor side.
- Theme Integration: Uses existing Strapi tokens including shadows (
filterShadow), borders (neutral150), and backgrounds (neutral0).
HoverCard Composable Usage
import { HoverCard } from 'strapi-design-extended';
import { Typography, Flex, Box, Avatar } from '@strapi/design-system';
function MyApp() {
return (
<HoverCard.Root>
<HoverCard.Trigger asChild>
<a href="https://github.com/strapi" target="_blank" rel="noreferrer">
@strapi
</a>
</HoverCard.Trigger>
<HoverCard.Content sideOffset={5}>
<Flex gap={3} alignItems="flex-start" style={{ width: '300px' }}>
<Avatar.Item src="https://avatars.githubusercontent.com/u/5428414?v=4" alt="Strapi" fallback="S" />
<Box>
<Typography fontWeight="bold" tag="div" fontSize={2}>
Strapi
</Typography>
<Typography textColor="neutral600" tag="div" fontSize={1}>
@strapi
</Typography>
<Typography tag="p" textColor="neutral800" fontSize={2} style={{ marginTop: '8px' }}>
The leading open-source headless CMS.
</Typography>
</Box>
</Flex>
</HoverCard.Content>
</HoverCard.Root>
);
}HoverElement Props Usage
import { HoverElement } from 'strapi-design-extended';
import { Typography, Flex, Box, Avatar } from '@strapi/design-system';
function MyApp() {
return (
<HoverElement
sideOffset={5}
trigger={
<a href="https://github.com/strapi" target="_blank" rel="noreferrer">
@strapi
</a>
}
>
<Flex gap={3} alignItems="flex-start" style={{ width: '280px' }}>
<Avatar.Item src="https://avatars.githubusercontent.com/u/5428414?v=4" alt="Strapi" fallback="S" />
<Box>
<Typography fontWeight="bold" tag="div" fontSize={2}>
Strapi
</Typography>
<Typography tag="p" textColor="neutral800" fontSize={2}>
The leading open-source headless CMS.
</Typography>
</Box>
</Flex>
</HoverElement>
);
}Toolbar
A container toolbar component based on Radix UI's Toolbar primitive, visually matching Strapi design system guidelines.
- Single vs Multiple Selection Groups: Supports multiple choice toggle sub-groups (multiple checkbox behavior) or single choice toggle sub-groups (radio group behavior).
- Auto-Selection: In
singleselection mode, if no default-selected item starts selected (valueordefaultValue), the first item's value is automatically chosen. - Strict Single-Selection Constraint: Single selection groups enforce that at least one option always remains active and selected; users cannot click to clear the selected item entirely.
- Sub-Component Integration: Integrates directly with standalone buttons, links, and separators formatted for perfect alignment.
Toolbar Usage
import { Toolbar } from 'strapi-design-extended';
import { Bold, Italic, AlignLeft, AlignCenter, Write } from '@strapi/icons';
function MyApp() {
return (
<Toolbar.Root aria-label="Formatting options">
{/* Multiple Selection Toggle Group */}
<Toolbar.ToggleGroup type="multiple" aria-label="Text formatting">
<Toolbar.ToggleItem value="bold" aria-label="Bold">
<Bold />
</Toolbar.ToggleItem>
<Toolbar.ToggleItem value="italic" aria-label="Italic">
<Italic />
</Toolbar.ToggleItem>
</Toolbar.ToggleGroup>
<Toolbar.Separator />
{/* Single Selection Toggle Group */}
<Toolbar.ToggleGroup type="single" defaultValue="center" aria-label="Text alignment">
<Toolbar.ToggleItem value="left" aria-label="Left aligned">
<AlignLeft />
</Toolbar.ToggleItem>
<Toolbar.ToggleItem value="center" aria-label="Center aligned">
<AlignCenter />
</Toolbar.ToggleItem>
</Toolbar.ToggleGroup>
<Toolbar.Separator />
<Toolbar.Link href="#" target="_blank">
Edited 2 mins ago
</Toolbar.Link>
<Toolbar.Button startIcon={<Write />} style={{ marginLeft: 'auto' }}>
Submit
</Toolbar.Button>
</Toolbar.Root>
);
}2. Hooks
useDesignTokens
A utility hook that integrates with the Strapi styled-components ThemeContext.
- Dynamic CSS Injection: Generates and injects CSS custom properties (prefixed with
--strapi-) into the document head when the theme changes. - Token Accessors: Provides getter functions for accessing various theme tokens, including:
borderRadius(token)breakpoint(token)color(token)fontSize(token)fontWeight(token)lineHeight(token)motion(token)shadow(token)size(token)space(token)transition(token)zIndex(token)
useDesignTokens Usage
import { useDesignTokens } from 'strapi-design-extended';
import { Typography } from '@strapi/design-system';
function ThemeConsumer() {
const { color } = useDesignTokens();
return (
<div style={{ backgroundColor: color('danger500'), padding: '1rem' }}>
<Typography variant="epsilon" textColor="neutral0">
This box uses the danger500 color from the design tokens.
</Typography>
</div>
);
}Development & Build Commands
Maintain and build the package locally using these npm scripts:
# Start Vite development playground/server
npm run dev
# Compile TypeScript type compiler check
npm run typecheck
# Build the ready-to-publish production package (dist/)
npm run buildFuture Roadmap
Additional components and utilities will be added to this library over time. Contributions and feature requests are welcome.
