Disclosure
An interactive component which expands/collapses content.
Jasmin starred 3 repositories
import { CaretUpDown, X } from '@examples/primitives/disclosure/icons'
import Disclosure from 'corvu/disclosure'
import type { VoidComponent } from 'solid-js'
const DisclosureExample: VoidComponent = () => {
return (
<div class="mt-8">
<Disclosure.Root collapseBehavior="hide">
{(props) => (
<>
<div class="mb-2 flex items-center justify-between space-x-4">
<p class="font-medium">Jasmin starred 3 repositories</p>
<Disclosure.Trigger class="rounded-lg bg-corvu-100 p-1 text-corvu-dark transition-all duration-100 hover:bg-corvu-200 active:translate-y-0.5">
{props.expanded && <X size="20" />}
{!props.expanded && <CaretUpDown size="20" />}
</Disclosure.Trigger>
</div>
<div class="rounded-lg bg-corvu-100 px-3 py-2 text-corvu-dark">
corvudev/corvu
</div>
<Disclosure.Content class="mt-1 space-y-1 overflow-hidden corvu-expanded:animate-expand corvu-collapsed:animate-collapse">
<div class="rounded-lg bg-corvu-100 px-3 py-2 text-corvu-dark">
solidjs/solid
</div>
<div class="rounded-lg bg-corvu-100 px-3 py-2 text-corvu-dark">
nitropage/nitropage
</div>
</Disclosure.Content>
</>
)}
</Disclosure.Root>
</div>
)
}
export default DisclosureExample
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
corvu: {
50: '#f2f0fe',
100: '#e6e2fd',
200: '#d4cbfb',
light: '#D4C0FF',
300: '#bcacf6',
400: '#a888f1',
500: '#9a6de9',
600: '#8f50dc',
700: '#7e41c3',
accent: '#7250AE',
800: '#63359c',
900: '#52317d',
dark: '#180f23',
1000: '#0C0812',
},
},
animation: {
expand: 'expand 250ms cubic-bezier(0.32,0.72,0,0.75)',
collapse: 'collapse 250ms cubic-bezier(0.32,0.72,0,0.75)',
},
keyframes: {
expand: {
'0%': {
height: '0px',
},
'100%': {
height: 'var(--corvu-disclosure-content-height)',
},
},
collapse: {
'0%': {
height: 'var(--corvu-disclosure-content-height)',
},
'100%': {
height: '0px',
},
},
},
},
},
plugins: [require('@corvu/tailwind')],
}
import { CaretUpDown, X } from '@examples/primitives/disclosure/icons'
import Disclosure from 'corvu/disclosure'
import type { VoidComponent } from 'solid-js'
const DisclosureExample: VoidComponent = () => {
return (
<div>
<Disclosure.Root collapseBehavior="hide">
{(props) => (
<>
<div class="header">
<p class="header_title">Jasmin starred 3 repositories</p>
<Disclosure.Trigger>
{props.expanded && <X size="20" />}
{!props.expanded && <CaretUpDown size="20" />}
</Disclosure.Trigger>
</div>
<div class="repository_card">corvudev/corvu</div>
<Disclosure.Content>
<div class="repository_card">solidjs/solid</div>
<div class="repository_card">nitropage/nitropage</div>
</Disclosure.Content>
</>
)}
</Disclosure.Root>
</div>
)
}
export default DisclosureExample
.header {
margin-bottom: 0.5rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.header> :not([hidden])~ :not([hidden]) {
margin-left: 1rem;
}
.header_title {
font-weight: 500;
}
[data-corvu-disclosure-trigger] {
border-radius: 0.5rem;
padding: 0.25rem;
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 100ms;
color: rgb(24 15 35);
background-color: rgb(230 226 253);
}
[data-corvu-disclosure-trigger]:active {
transform: translate(0, 0.125rem);
}
[data-corvu-disclosure-trigger]:hover {
background-color: rgb(212 203 251);
}
.repository_card {
border-radius: 0.5rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: rgb(24 15 35);
background-color: rgb(230 226 253);
}
[data-corvu-disclosure-content] {
margin-top: 0.25rem;
overflow: hidden;
}
.space-y-1 > :not([hidden]) ~ :not([hidden]){
margin-top: 0.25rem;
}
[data-corvu-disclosure-content][data-collapsed] {
animation: collapse 200ms linear;
}
[data-corvu-disclosure-content][data-expanded] {
animation: expand 200ms linear;
}
@keyframes expand {
0% {
height: 0px;
}
100% {
height: var(--corvu-disclosure-content-height);
}
}
@keyframes collapse {
0% {
height: var(--corvu-disclosure-content-height);
}
100% {
height: 0px;
}
}
Features
- Option to hide the content when collapsed instead of unmounting it for better SEO
- CSS variables to animate the height/width of the content
- Full keyboard navigation
Usage
import Disclosure from 'corvu/disclosure'
// Or
// import { Root, Trigger, ... } from 'corvu/disclosure'
Anatomy
<Disclosure.Root>
<Disclosure.Trigger />
<Disclosure.Content />
</Disclosure.Root>
Animation
Corvu sets the --corvu-disclosure-content-height
and --corvu-disclosure-content-width
CSS properties on the disclosure content that make it possible to animate the height/width.
[data-corvu-disclosure-content][data-collapsed] {
animation: collapse 200ms linear;
}
[data-corvu-disclosure-content][data-expanded] {
animation: expand 200ms linear;
}
@keyframes collapse {
0% {
height: var(--corvu-disclosure-content-height);
}
100% {
height: 0px;
}
}
@keyframes expand {
0% {
height: 0px;
}
100% {
height: var(--corvu-disclosure-content-height);
}
}
Accessibility
Adheres to the Disclosure WAI-ARIA design pattern.
Keyboard navigation
Key | Behavior |
---|---|
Space | Activates the trigger and toggles the disclosure. |
Enter | Activates the trigger and toggles the disclosure. |
API reference
Disclosure.Root
Component
Context wrapper for the disclosure. Is required for every disclosure you create.
Props
expanded
boolean
Whether the disclosure is expanded or not.
onExpandedChange
(expanded: boolean) => void
Callback fired when the expanded state changes.
initialExpanded
boolean
Whether the disclosure is expanded initially or not. *Default = false
*
collapseBehavior
'remove' | 'hide'
Whether the disclosure content should be removed or hidden when collapsed. Useful if you want to always render the content for SEO reasons. *Default = remove
*
disclosureId
string
The id
attribute of the disclosure content element. *Default = A unique id.*
contextId
string
The id
of the disclosure context. Useful if you have nested disclosures and want to create components that belong to a disclosure higher up in the tree.
children
JSX.Element | (props: DisclosureRootChildrenProps) => JSX.Element
Disclosure.Trigger
Component
Button that changes the open state of the disclosure when clicked.
Props
as
ValidComponent
Default: button
Component to render the polymorphic component as. *Default = div
*
asChild
boolean
Whether to render the polymorphic component as the first <As />
component found in its children. *Default = false
*
contextId
string
The id
of the disclosure context to use.
Data
Data attributes present on primitives/disclosure.Trigger components.
data-corvu-disclosure-trigger
Present on every disclosure trigger element.
data-expanded
Present when the disclosure is expanded.
data-collapsed
Present when the disclosure is collapsed.
CSS props
CSS properties attributes present on primitives/disclosure.Trigger components.
Disclosure.Content
Component
Content of a disclosure. Can be animated.
Props
as
ValidComponent
Default: div
Component to render the polymorphic component as. *Default = div
*
asChild
boolean
Whether to render the polymorphic component as the first <As />
component found in its children. *Default = false
*
forceMount
boolean
Whether the disclosure content should be forced to render. Useful when using third-party animation libraries.
contextId
string
The id
of the disclosure context to use.
Data
Data attributes present on primitives/disclosure.Content components.
data-corvu-disclosure-content
Present on every disclosure content element.
data-expanded
Present when the disclosure is expanded.
data-collapsed
Present when the disclosure is collapsed.
CSS props
CSS properties attributes present on primitives/disclosure.Content components.
--corvu-disclosure-content-width
The width of the disclosure content. Useful if you want to animate its width.
--corvu-disclosure-content-height
The height of the disclosure content. Useful if you want to animate its height.
Disclosure.useContext
Context
Context which exposes various properties to interact with the disclosure. Optionally provide a contextId to access a keyed context.
Returns
expanded
Accessor<boolean>
Whether the disclosure is expanded or not.
setExpanded
Setter<boolean>
Callback fired when the expanded state changes.
collapseBehavior
Accessor<'remove' | 'hide'>
Whether the disclosure content should be removed or hidden when collapsed.
disclosureId
Accessor<string>
The id
attribute of the disclosure content element.
contentPresent
Accessor<boolean>
Whether the disclosure content is present. This differes from expanded
as it tracks pending animations.
contentRef
Accessor<HTMLElement | null>
The disclosure content element.
contentSize
Accessor<[number, number] | null>
The current size of the disclosure content. Useful if you want to animate width or height. [width, height]
Disclosure.RootChildrenProps
Type
Props which are passed to the Root component children function.
Props
collapseBehavior
'remove' | 'hide'
Whether the disclosure content should be removed or hidden when collapsed.
contentPresent
boolean
Whether the disclosure content is present. This differes from expanded
as it tracks pending animations.
contentRef
HTMLElement | null
The disclosure content element.
contentSize
[number, number] | null
The current size of the disclosure content. Useful if you want to animate width or height. [width, height]
disclosureId
string
The id
attribute of the disclosure content element.
expanded
boolean
Whether the disclosure is expanded or not.
setExpanded
Setter<boolean>
Callback fired when the expanded state changes.
corvu@0.2.3
Developed and designed by Jasmin